!standard 4.09 (29) 01-09-20 AI95-00269/03 !class binding interpretation 01-02-22 !status work item 01-05-25 !status received 01-03-23 !qualifier Omission !priority Medium !difficulty Medium !subject Generic formal objects can be static in the instance !summary If a formal in object is associated with a static actual, uses of the formal object declared in an instance outside of that instance are static. !question Is the use of a formal object within a generic instance treated as static if the formal object is associated with a static actual? (Yes, when used outside of the instance.) Consider the following example: procedure Ex_1 is generic B1 : in Boolean; package Gen_1 is C1 : constant Boolean := B1; end Gen_1; B_True : constant Boolean := True; package New_Gen_1 is new Gen_1 (False); begin case B_True is when New_Gen_1.C1 => -- Legal? (Yes.) null; when not New_Gen_1.C1 => -- Legal? (Yes.) null; end case; end Ex_1; !recommendation (See summary.) !wording (See corrigendum.) !discussion AI83-00001 concludes that, outside the instance, an expression is static if all the names in this expression "denote" static things. However, 4.9(24) says that a static constant is declared by a full constant declaration. But a formal object in an instance is not declared by a full constant declaration, and thus a formal object can never be static. This would be a significant incompatibility with Ada 83. Thus, formal objects with static actual expressions should be treated as static in the instance. However, we need to be careful. We do not want to require exact evaluation for expressions static because of a formal object inside of the generic unit, because that would interfere with generic sharing. We also do not want to trigger any of the other rules of 4.9(34-38). All of these would require evaluating the expression when the generic is instantiated, which would introduce a body dependence. Note that generic formal objects cannot be used in a context where a static expression is required inside of the generic, as legality rules are checked in the generic unit based on the properties of the formal (see 12.3(11)). Thus, any such use would be illegal in the generic unit. !corrigendum 4.09(37) @dinsa The last two restrictions above do not apply if the expected type is a descendant of a formal scalar type (or a corresponding actual type in an instance). @dinst If a static expression appears in an instance body and the expression is non-static in the generic body, then none of the legality rules for static expressions apply to the expression in the instance. !ACATS test Legacy tests A49027A, A49027B, and A49027C test cases where items that are non-static in the generic specification are static in the instance specification. !appendix From: Gary Dismukes Sent: Friday, March 23, 2001 7:23 PM This is a question about an interaction between static expressions and generic instances. It came up as a result of a user of GNAT running into a somewhat obscure warning involving an expression within a generic (in the context of an instantation). The basic question comes down to whether the use of a formal object within a generic instance is to be treated as static if the formal object is associated with a static actual. (This could be broadened to include static properties of other formals, but we'll limit this to formal objects to focus the discussion.) Consider the following examples: -- Example 1: procedure Ex_1 is generic B1 : in Boolean; B2 : in out Boolean; package Gen_1 is C1 : constant Boolean := B1; C2 : constant Boolean := B2; end Gen_1; B_True : constant Boolean := True; package New_Gen_1 is new Gen_1 (False, B_True); begin case B_True is when New_Gen_1.C1 => -- Legal? null; when New_Gen_1.C2 => -- Legal? null; end case; end Ex_1; -- Example 2: procedure Ex_2 is generic type T is range <>; One : T; Zero : T := 0; package Gen_2 is Bang : T := One / Zero; end Gen_2; package New_Gen_2 is new Gen_2 (Integer, 1); -- Is this instantiation illegal, because of division by zero? begin null; end Ex_2; -- End of examples -- The AARM gives the following general rule about instances: 13 The instance is a copy of the text of the template. [Each use of a formal parameter becomes (in the copy) a use of the actual, as explained below.] ... and elaborates with some annotations: ... 13.c We describe the substitution of generic actual parameters by saying (in most cases) that the copy of each generic formal parameter declares a view of the actual. Suppose a name in a generic unit denotes a generic_formal_parameter_declaration. The copy of that name in an instance will denote the copy of that generic_formal_ parameter_declaration in the instance. Since the generic_formal_ parameter_declaration in the instance declares a view of the actual, the name will denote a view of the actual. 13.d Other properties of the copy (for example, staticness, classes to which types belong) are recalculated for each instance; this is implied by the fact that it's a copy. Looking specifically at the rules for formal objects, 12.4(10) says: 10 {stand-alone constant (corresponding to a formal object of mode in)} In an instance, a formal_object_declaration of mode in declares a new stand-alone constant object whose initialization expression is the actual, whereas a formal_object_declaration of mode in out declares a view whose properties are identical to those of the actual. The above paragraphs suggest that in an instance where the actual is a static expression (or name denoting a static constant in the case of mode in out), the name of a formal object denotes a constant initialized by that static expression (for mode in), or declares a view of a static constant (for mode in out). Certainly in the case of the in out formal, it would seem that the intent is that within an instance the name of this formal denotes a static constant ("has properties identical to those of the actual"). This interpretation would seem to make Example 1 legal and Example 2 illegal. However, the definition of a static constant specifies (4.9(24)): 24 {static (constant)} A static constant is a constant view declared by a full constant declaration or an object_renaming_declaration with a static nominal subtype, having a value defined by a static scalar expression or by a static string expression whose value has a length not exceeding the maximum length of a string_literal in the implementation. Given this definition, it would seem that the constant or view declared for a formal object in an instance could never be a static constant, since it is does not satisfy the (syntax-based) requirements for being a static constant. This would seem to imply that Example 1 is illegal and Example 2 is legal. GNAT currently follows the first interpretation (i.e., it treats uses of formals as static within an instance when the actuals are static), but there's some debate about whether this is correct. Regardless of the answer, I think it would be useful to have an ACATS test that checks this, to ensure that compilers implement a consistent interpretation. **************************************************************** From: Randy Brukardt Sent: Friday, March 23, 2001 7:51 PM This seems to be a similar question to the one asked in AI-00263 (Scalar formal derived types are never static), and it seems that we would probably want the same answer. (Of course, the answer in that AI is the view of a small number of people in an E-Mail discussion, so I wouldn't pay too much attention to the conclusions, yet.) That question came up in the context of the enumeration extension discussion, but it became clear that the question has nothing to do with enumeration extensions, and everything to do with a language design issue. The contention of the person who brought up this question is that the value of a static expression should not be different in different instantiations. If you buy his contention (which I do), then it is clear that staticness as in Gary's examples needs to be prohibited. OTOH, if you DON'T buy this "design principle", then probably Gary's examples are correct. In any case, I would think that this question and that one should be handled together. I'll add this mail and succeeding discussion to that AI. > Regardless of the answer, I think it would be useful to have an > ACATS test that checks this, to ensure that compilers implement > a consistent interpretation. From a pure testing perspective, I'd agree with you. But, as your boss likes to say, the mere presence of a potential portability problem isn't alone a good enough reason for a test -- there also has to be a probability that users will bump into the problem. Since this issue has stayed under the rug for the entire life of Ada 95, I can't get too excited about its importance. (Of course, once an AI is approved, a test objective will get added to the next ARG ballot, and we'll go from there.) **************************************************************** From: Robert Dewar Sent: Friday, March 23, 2001 7:30 PM In the event that the answer to this is that the formal in the spec *is* a static expression (I believe it isn't because of para 24, but it's arguable), we have to ask if the formal would be a static expression in the body. Surely the answer must be no, or we have horrible contract/shared generic problems. But where in the RM does it provide a hint that the spec/body are different in this particular respect? **************************************************************** From: Tucker Taft Sent: Friday, March 23, 2001 7:56 PM Our compiler certainly treats formal objects as potentially static, determined by the staticness of the actual. I think there is general agreement that this is the "right" way to do things, and we have discussed other AIs, I believe, which presumed this was true (e.g. the one about the rules for formal package matching). I presumed there already were some ACATS tests that checked the potential staticness of formal objects, because it was certainly a lot of work to get it right. **************************************************************** From: Robert Dewar Sent: Friday, March 23, 2001 8:34 PM Does it do this in bodies as well? Because if it does, then you get significant contract violations, n'est-ce-pas? That's the way GNAT behaves, the expression is static in the spec instance, and in the body, it is considered non-static. For example, this program is illegal: procedure m is generic zero : integer := 0; package x is vvv : integer := 1 / zero; end; package body x is end x; package rr is new x (0); begin null; end; m.adb:12:04: instantiation error at line 6 m.adb:12:04: division by zero m.adb:12:04: static expression raises "constraint_error" But the following program is legal: procedure m is generic zero : integer := 0; package x is end; package body x is vvv : integer := 1 / zero; end x; package rr is new x (0); begin null; end; And generates the warnings: m.adb:12:04: warning: in instantiation at line 9 m.adb:12:04: warning: division by zero m.adb:12:04: warning: "constraint_error" will be raised at run time ---------- We actually noticed this in GNAT as a result of the rule that requires biased rounding of floating-point in static expressions (and of course we provide proper unbiased rounding for non-static expressions, even if they are folded at compile time). So we were getting a warning on this biased rounding. **************************************************************** From: Gary Dismukes Sent: Friday, March 23, 2001 9:02 PM Robert responded to Tuck: > < static, determined by the staticness of the actual. I think > there is general agreement that this is the "right" way to > do things, and we have discussed other AIs, I believe, which > presumed this was true (e.g. the one about the rules for > formal package matching). > >> > > does it do this in bodies as well? Because if it does, then you > get significant contract violations, n'est-ce-pas? There's a rule that legality rules aren't rechecked in instance bodies, which I presume Intermetrics/Averstar compiler follows (I think there are some tests for that). > That's the way GNAT behaves, the expression is static in the spec instance, > and in the body, it is considered non-static. From a legality point of view GNAT is indeed not checking the expression in the body, but the warning about biased rounding was happening because the compiler was still treating the expression evaluation as static in the instance body, n'est-ce pas? **************************************************************** From: Robert Dewar Sent: Friday, March 23, 2001 9:40 PM That's a completely independent problem, nothing to do with the basic question at hand here. **************************************************************** From: Tucker Taft Sent: Friday, March 23, 2001 10:26 PM We do it everywhere, I believe, but don't do any legality checks during body instantiation. **************************************************************** From: Robert Dewar Sent: Saturday, March 24, 2001 3:33 AM But then surely you get things wrong in the body. in particular, let's address the case that brought this up in the first place. There is a (to us very annoying) rule that requires that floating-point rounding be done wrong for static expressions (i.e. in a biased manner). We have the option of generating a warning for this, but obviously you do not want to do such not-the-same-as-run-time-rounding unless you have to, so we do not want to do it in bodies. Also, is it really the case that you do no legality checks in the body? That's surely wrong for the cases on which we have agreed that contract violations are OK, notably for certain cases of pragma restrictions, and also as I remember some rep clause cases. **************************************************************** From: Pascal Leroy Sent: Monday, March 26, 2001 1:44 AM > generic > B1 : in Boolean; > B2 : in out Boolean; > package Gen_1 is > C1 : constant Boolean := B1; > C2 : constant Boolean := B2; > end Gen_1; > > B_True : constant Boolean := True; > > package New_Gen_1 is new Gen_1 (False, B_True); > > begin > case B_True is > when New_Gen_1.C1 => -- Legal? > null; > when New_Gen_1.C2 => -- Legal? > null; > end case; I think this example is a red herring. The instantiation is illegal because the actual corresponding to B2 has to be a variable (RM95 12.4(7)). So, happily enough, we don't have to argue about the staticness of C2... > procedure Ex_2 is > > generic > type T is range <>; > One : T; > Zero : T := 0; > package Gen_2 is > Bang : T := One / Zero; > end Gen_2; > > package New_Gen_2 is new Gen_2 (Integer, 1); > > -- Is this instantiation illegal, because of division by zero? Yes, obviously the instantiation is illegal because of division by zero, and One/Zero is static in the spec (this follows from RM95 12.4(10)). As Robert pointed out, the same expression in the body would not be static, and it would raise C_E at execution, and a warning would be user-friendly. This follows from RM95 12.3(11). **************************************************************** From: Robert Dewar Sent: Monday, March 26, 2001 8:10 AM <> I really don't understand the obviously here. I don't understand why the occurrence of One is static according to the 4.9 rules, since I don't see any constant declaration. I understand that One is a constant, I just don't see the declaratoin required by the 4.9 rules. **************************************************************** From: Pascal Leroy Sent: Monday, March 26, 2001 8:21 AM > I really don't understand the obviously here. I don't understand why the > occurrence of One is static according to the 4.9 rules, since I don't > see any constant declaration. RM95 12.4(10): "In an instance, a formal_object_declaration of mode in declares a new stand-alone constant object whose initialization expression is the actual..." Therefore, One is a constant in every instantiation. Moreover, in the instantiations where the actual expression is static, One is a static constant. The same applies to Zero. Thus, in the instantiation in question One/Zero is a static expression. (It is static both in the body and in the spec of the instantiation, but the legality rules don't matter in the body.) I am not sure what we are arguing about. This seems pretty straightforward to me (at least in Ada 95; Ada 83 was muddled in this area). **************************************************************** From: Robert Dewar Sent: Monday, March 26, 2001 8:55 AM <> This says that the constant object is declared, but my reading of 4.9(24) says that the constant object must be declared by a full constant declaration -- I do not see this here. Note that the reason this is significant is because we are not just talking about whether static expressions dividing by zero cause warnings or errors, which is not particularly critical, but rather whether the annoying "wrong" compile time rounding rule (biased, always away from 0.0) applies to floating-point expressions. THat's why we care :-) **************************************************************** From: Pascal Leroy Sent: Monday, March 26, 2001 9:03 AM > This says that the constant object is declared, but my reading of > 4.9(24) says that the constant object must be declared by a full > constant declaration -- I do not see this here. > > Note that the reason this is significant is ... whether the annoying > "wrong" compile time rounding rule (biased, always away from 0.0) applies > to floating-point expressions. I have some sympathy for the notion of fixing the rounding rule (I assume that you want round-to-nearest even, right?). However, if that's what we want to do, let's do it by changing 4.9(38), not by dubious theological interpretation of the staticness of constants declared in an instance. **************************************************************** From: Robert Dewar Sent: Monday, March 26, 2001 9:17 AM <> Well fixing the rounding rule would be nice, but the question right now is where it applies, and where it doesn't. This is not theology, it is about what results you get (and in our case whether we issue the warning about unexpected rounding). You still did not answer the "theological" questions about 4.9(24), whose reading seems pretty straightforward to me. **************************************************************** From: Gary Dismukes Sent: Monday, March 26, 2001 1:54 PM Pascal wrote: > > I think this example is a red herring. The instantiation is illegal because > the actual corresponding to B2 has to be a variable (RM95 12.4(7)). So, > happily enough, we don't have to argue about the staticness of C2... Yes, the mention of in out parameters was a mistake, so only the in formal case is relevant (so the example is only half a red herring :). > Yes, obviously the instantiation is illegal because of division by zero, and > One/Zero is static in the spec (this follows from RM95 12.4(10)). That was my interpretation as well, but Robert takes issue based on the definition of static constant in 4.9(24) as explained in my first posting. (It's always been my understanding that these things are static in instance specs, but we don't have agreement on that and there may be a wording issue to resolve.) > As Robert pointed out, the same expression in the body would not be static, > and it would raise C_E at execution, and a warning would be user-friendly. > This follows from RM95 12.3(11). It's interesting that you say that in the body it would not be static, because in a subsequent message you stated (see last sentence): Pascal(2) wrote: > Therefore, One is a constant in every instantiation. Moreover, in the > instantiations where the actual expression is static, One is a static constant. > The same applies to Zero. Thus, in the instantiation in question One/Zero is a > static expression. (It is static both in the body and in the spec of the > instantiation, but the legality rules don't matter in the body.) I agree that the legality rules don't matter in the body. The question that raised this whole issue is whether the expression is static in the body, because if it is, then presumably static arithmetic rules apply, which means that it would seem rounding needs to be done according to the rules of 4.9(38). But presumably that can't possibly be intended because it would be a major hardship for shared generics. It seems though, that if an expression involving a generic formal parameter can be static in an instance spec (as I believe), that by 12.3(13) (and as explained by 12.3(13.d)) it can also be static in the instance body, which leads to this problem. So something seems to be broken here if this interpretation is correct. **************************************************************** From: Robert Dewar Sent: Monday, March 26, 2001 2:14 PM <> Indeed, I agree here. *if* it is the case that the expression is static in the instance spec, then I see no rule which would differentiate this from the instance body. Note that we are not just talking about rounding here, if the expression is static in the instance body, that requires full run-time multiple-precision arithmetic for the shared generic case. **************************************************************** From: Tucker Taft Sent: Monday, March 26, 2001 5:35 PM There seems to be agreement that a formal IN object initialized with a static actual should be: 1) static in the spec 2) non-static in the body I agree that the RM does not say this, and that we need an AI to appropriately "interpret" it this way. **************************************************************** From: Robert Dewar Sent: Monday, March 26, 2001 9:24 PM I agree this is an AI that is definitely needed. **************************************************************** From: Pascal Leroy Sent: Tuesday, March 27, 2001 3:12 AM > > As Robert > > pointed out, the same expression in the body would not be static, and it would > > raise C_E at execution, and a warning would be user-friendly. This follows from > > RM95 12.3(11). > > It's interesting that you say that in the body it would not be static, > because in a subsequent message you stated (see last sentence): > > Pascal(2) wrote: > > Therefore, One is a constant in every instantiation. Moreover, in the > > instantiations where the actual expression is static, One is a static constant. > > The same applies to Zero. Thus, in the instantiation in question One/Zero is a > > static expression. (It is static both in the body and in the spec of the > > instantiation, but the legality rules don't matter in the body.) Ok, so much for consistency. I agree that the RM should be fixed, and that the constant should not be static in the body. **************************************************************** From: Randy Brukardt Sent: Wednesday, March 28, 2001 4:43 PM Before I try to write this up, I want to make sure that it is clear exactly what we are talking about. There are really 4 places to consider for a generic: 1) The generic specification; 2) The generic body; 3) The instance specification; and 4) The instance body. For an implementation using generic sharing, there really isn't any such thing as a "instance body". The generic body is used for all instances. Thus, we want the rules to have the same effect for (2) the generic body and (4) the instance body. For this case, it's clear that we want OTOH, that isn't so critical for (1) and (3). Indeed, in this case, we really want different answers. Otherwise, we have a "hidden" contract, and generic sharing can be prohibitively expensive. Indeed, the current wording of 4.9(24) is that way for a reason (well, several reasons, only one of which matters to this discussion). That is, we didn't want formal objects to be treated as static in the generic specification. However, for Ada 83 compatibility, we did want these things to be static in the instance specification. What does this mean? The items might be static when used outside of the generic, but never inside of the generic. Let me give an example (based on Gary's): generic I1 : in Integer; I2 : in Integer; package A_Generic is subtype Short_Int is Integer range I1 .. I2; -- (1) type Another_Int is range 0 .. (2**I2)-1; -- (2) for Another_Int'Size use I2; -- (3); type Some_Record is record Len : Boolean; Comp1 : Another_Int; end record; for Some_Record use record Comp1 at 0 range 0 .. I2-1; -- (4) Len at 0 range I2 .. I2+7; end record; end A_Generic; All of (2), (3), and (4) are illegal by 4.9(24), and this is intended. (1) doesn't require a static item, and thus is legal. Otherwise, the representation of Another_Int and Some_Record would be different for different instantiations. The only way to implement these would be as if they are generic formal derived parameters, and this would have the effect of a 'hidden' contract. Moreover, the implementation of Some_Record would be prohibitively expensive (as the components would have the located at runtime). (Luckily, generic formal derived untagged record types are rare, so they *can* be that expensive.) OTOH, uses of the objects declared in the instance *outside* of the generic can be static. That was required by Ada 83 (and tested by a controversial ACVC test), and thus must be true in order to keep compatibility. For instance: package An_Instantiation is new A_Generic (I1 => 1, I2 => 16); Var : An_Instantiation.Short_Int; ... case Var is when An_Instantiation.Short_Int'First => ... -- OK when An_Instantiation.Short_Int'First+1 .. An_Instantiation.Short_Int'Last => ... -- OK end case; -- OK, no others required. It's clear that the RM language does not provide the latter at all; items derived from a generic object are never static, because a generic formal or actual object can never meet the requirements of 4.9(24). What we want is to preserve the properties mentioned above. 12.3(11) should be helpful, since it is says that Legality Rules are enforced in the generic_declaration given the properties of the formals. The AARM also notes that 4.9(24) is intended to exclude deferred constants. Clearly, we also want to continue to exclude generic formal objects other than in an instance. As far as I know, the only non-legality rule that apply to static expressions are those in 4.9(38). (12.3(11) seems to cover all of the Legality Rules sufficiently, because they are not checked in the instance body, which is what we need). So, it appears to me that what we need to do is modify 4.9(24) to explicitly include generic formal objects of mode 'in' in an instance, and modify 4.9(38) to exclude these as we do with formal scalar types. For 4.9(24), I'd suggest wording like: A static constant is a constant view declared by a full constant declaration, an object_renaming declaration, or a formal_object_declaration of mode 'in' in an instance with a static nominal subtype, .... ['in' would be in bold in the actual RM wording.] For 4.9(38), I'm not quite sure what to say. We don't want this rule to apply instance bodies to any expression to which it does not apply in the Generic_Body. Perhaps just saying that: If the static real expression occurs in an instance body, and is not a static expression in the generic_body, then no special rounding or truncating is required -- normal accuracy rules apply. If we applied the above to the entire instance, then the last sentence of 4.9(38) is unnecessary (because a formal scalar type can never be static in the generic_declaration or generic_body, only in an instance). Perhaps we delete the last sentence of 4.9(38) to the above, and make this rule apply in any part of an instance: If the static real expression occurs in an instance, and is not a static expression in the generic_declaration or generic_body, then no special rounding or truncating is required -- normal accuracy rules apply. Or we could just repeal 4.9(38) altogether -- but that seems like a different AI. Does the above make sense? If so, I will update the write-up of AI-00263 to include this. **************************************************************** From: Robert Dewar Sent: Wednesday, March 28, 2001 10:20 PM I must say on further reflection, I find it mighty odd that an expression like x+0.1 is of course the same in the body and the spec if x (a formal object) has a dynamic value, but if the x is static, then the expression might be required to be different, in other words, there are values of x for which the instantiation of the following generic is required to print FAILED. That seems mighty odd to me! generic x : float; package y is z1 : float := x + 0.1; end y; with Text_IO; use Text_IO; package body y is z2 : float := x + 0.1; begin if z1 /= z2 then Put_line ("FAILED"); end if; end y; This can happen on a machine with unbiased rounding at run time (the normal IEEE default) where in the spec, the RM requires biased rounding. So unless this anomoly is otherwise fixed, I would prefer that the relevant expressions both be considered non-static (which is what I think the RM says now anyway). **************************************************************** From: Randy Brukardt Sent: Wednesday, March 28, 2001 10:37 PM > So unless this anomoly is otherwise fixed, I would prefer that the relevant > expressions both be considered non-static (which is what I think the RM > says now anyway). This was my second alternative to the wording fix for 4.9(38), and this is a good reason for adopting that. Note that under no interpretation are these expressions ever static in the generic_declaration or generic_body; the only case where they might be static is in any instance. And the rounding and "infinite precision" issues are the only ones that might matter. Since code generation for the generic may occur at the point of the generic_body, we can't have rules that depend on the instantiation. I would argue that we don't want rules that give different answers in the generic_declaration/body and in the instance. Thus it makes the most sense to suspend any non-legality staticness rules inside the instance when the item in question is not static in the generic_declaration/body. But, we probably do want the "infinite precision" rules to apply to uses of static instance values (that are non-static in the generic_declaration/body) when they are used outside of the instance. (We can't just declare these things to be non-static because of the compatibility problem, even though that would be easiest.) What a mess! **************************************************************** From: Randy Brukardt Sent: Wednesday, March 28, 2001 10:44 PM I neglected to say in my previous message that Z1 can't be considered non-static, (even though that is what the RM says, and certainly would be easiest to deal with), because Ada 83's ACVC insisted that such things are static, at least when used outside of the generic. I'm pretty sure that test is still there (although I don't know the number off-hand). So, I don't think we have the easy option of declaring it non-static -- I think Ada compiler customers would be surprised and unhappy. (And then Robert would be arguing the other position of the same issue -- let's not go there!!) **************************************************************** From: Robert Dewar Sent: Wednesday, March 28, 2001 10:46 PM One possibility would be to eliminate the obnoxious rounding rule. I must say I never noticed this during review, and it seems quite horrible to me3 to require that static expressions get the wrong result. As for infinite precision, well you are always free to use infinite precision in evaluating expressions anway, because of 11.6 stuff (I must say I can't understand the new 11.6, but it must allow out of range intermediate values :-) Of course to *require* the infinite precision in the body would be disastrously wrong. **************************************************************** From: Robert Dewar Sent: Wednesday, March 28, 2001 10:52 PM <> I agree that we can't change current practice, and remember that both the Intermetrics front end (I call it that because that's what it used to be, and we can't keep renaming it :-) and GNAT currently treat the stuff in the spec as static, and in fact both play the trick of treating stuff in the body as static but not giving error messages (which mean that both get the rounding wrong in the body). This whole thing came up because in GNAT we introduced a warning when incorrect rounding is forced by the RM rules, and then were surprised when this message unexpectedly occurred in a generic body. **************************************************************** From: Pascal Leroy Sent: Thursday, March 29, 2001 2:21 AM > So unless this anomoly is otherwise fixed, I would prefer that the relevant > expressions both be considered non-static (which is what I think the RM > says now anyway). As Randy mentioned, this is absolutely unacceptable for compatibility reasons, especially since it has been that way since Ada 83 (as I recall this was muddled in the Ada 83 RM but was clarified by one of the first Ada 83 AIs). **************************************************************** From: Robert Dewar Sent: Thursday, March 29, 2001 5:09 AM <> Can you point to this AI, it would help inform the current discussion, and in some sense would be decisive on the issue, since we intend to be back compatible with both the Ada 83 RM and relevant AI's. **************************************************************** From: Pascal Leroy Sent: Thursday, March 29, 2001 6:23 AM > Can you point to this AI, it would help inform the current discussion, and > in some sense would be decisive on the issue, since we intend to be back > compatible with both the Ada 83 RM and relevant AI's. AI83-00001 makes a subtle-but-significant distinction between "denotes" and "declares". RM83 12.3(6-14) then uses "denotes" all over the place. The conclusion is that, outside the instance, an expression is static if all the names in this expression "denote" static things. (I must admit that 15 years later the logic seems a bit tenuous, but it was quite convincing at the time.) This was deemed important for the usability of generics. **************************************************************** From: Randy Brukardt Sent: Thursday, March 29, 2001 6:16 PM > One possibility would be to eliminate the obnoxious rounding rule. I must > say I never noticed this during review, and it seems quite horrible to me > to require that static expressions get the wrong result. That's probably the best solution to that part of the problem, but it doesn't solve the compatibility problem (the RM says that expressions derived from formal objects are not static, but clearly this is different from both Ada 83 and current practice). > As for infinite precision, well you are always free to use infinite > precision in evaluating expressions anyway, because of 11.6 stuff (I > must say I can't understand the new 11.6, but it must allow out of > range intermediate values :-) > > Of course to *require* the infinite precision in the body would be > disastrously wrong. Right, and that's the second problem. It is quite easy to tell if you are using infinite precision in the generic (just use a variation of the 0.3333....33 /= 16#0.1# check). We certainly don't want to require it in the body, and I would argue that you don't really want to require it in the spec, either. Otherwise, you have expressions that (potentially) give different answers in the spec and in the body of a generic. To me, at least, it make the most sense that these things are treated as static only outside of the instance. But this is not a major issue. Whether or not it is static in the generic spec, we're going to have the weird situation of a static expression (in the instance, at a minimum the instance body) to which 4.9(33) and the following do not apply. THAT is weird, and seems like it will be tough to word meaningfully. **************************************************************** From: Pascal Leroy Sent: Friday, March 30, 2001 2:37 AM > It is quite easy to tell if you are > using infinite precision in the generic (just use a variation of the > 0.3333....33 /= 16#0.1# check). We certainly don't want to require it in the > body, and I would argue that you don't really want to require it in the > spec, either. But, Randy, there is nothing specific to generics here. You can have very strange problems if for instance you modify a subtype bound so that it becomes non-static during maintenance. Static computations will become non-static, and they may yield vastly different results. But these are merely the pitfalls of using floats. The result of the above comparison might change based on details of the generated code, optimization level, etc., so regardless of staticness you probably don't want to do things like that. In general, you are in a state of sin as soon as you use literals that are not machine numbers (note that 'Machine helps a lot in Ada 95). **************************************************************** From: Randy Brukardt Sent: Friday, April 06, 2001 6:59 PM > note that this discussion got hijacked by a really-completely-irrelevant > discussion of rounding to integer. Can we get it back where it was, and > ask if we can reconsider the requirement for biased rounding of floating-point > constants (well static expressions in general, but it is constants where > it is most offensive!) Well, really the rounding of floating-point constants discussion had hijacked the discussion of staticness for generic formal objects, and then that was hijacked again. Indeed, there are three issues that we've discussed: 1) Generic formal objects aren't static in the instance by the RM, although all (?) compilers implement them as such. And that is necessary for Ada 83 compatibility (AI83-00001). Care must be taken when fixing this to insure that such objects are not required to be static in the body, otherwise we would be requiring static rounding and exact evaluation in shared generic bodies. Which led to the second discussion: 2) Do we really want the biased rounding of floating point static expressions? It provides different answers than occur when the same expression is evaluated at run-time. That had been required by analogy to the real => integer conversion rule, which then led to: 3) Real => Integer conversions can be pretty expensive. How do we write fast conversions in Ada 95? At this point, all of these discussions are attached to an existing AI on generic staticness. I don't think (2) and especially (3) are related enough to (1) and the other topic in AI-0263, so I think they will need their own AI(s). Note that changing (2) does not eliminate the need to handle (1), and vice versa. **************************************************************** From: Robert Dewar Sent: Friday, April 06, 2001 7:16 PM Quite so. the relation between (2) and (1) is simply that the GNAT warning for (2) dug up (1) :-) **************************************************************** From: Pascal Leroy Sent: Wednesday, September 19, 2001 10:18 AM > A @i is a constant view declared by a full constant > declaration, an @fa with a static nominal > subtype, or generic formal object of mode @b declared in an instance and > used outside of the instance having a value defined by a static scalar > expression or by a static string expression whose value has a length not > exceeding the maximum length of a @fa in the implementation. I don't think that "used outside of the instance" works, because a generic formal object of mode in is never usable outside of the instance. It can be used in another declaration, which is itself exported by the instance (e.g. B1 is used in the declaration of C1 above). I suggest removing "and used outside of the instance". **************************************************************** From: Randy Brukardt Sent: Wednesday, September 19, 2001 10:31 PM I told you I wasn't happy with the wording. :-) However, removing "and used outside the instance" causes the problem of exact evaluation inside the generic unit instance to reappear. (Well, you would say it was never gone.) The issue is that inside the instance, anything these things touch need to be treated if they are non-static, and outside the instance, those expressions must be static. For generic sharing reasons, we do not want to require exact evaluation of these expressions, especially in the generic body. (Other legality rules are checked in the generic unit, so those rules are not a problem.) The problem is that the current wording for staticness doesn't have an provision for a "view" that is static and one that is not. That makes it very difficult to write this rule, which presumably is why it was left out of Ada 95 in the first place. It also shows why the Ada 83 rule was a mistake -- but that's irrelevant. Given that my last attempt to do this failed, I think the most likely fix would be to try to change 4.9(33) to except expressions that are derived for a generic formal object from the exactness requirement. However, I can't think of any way to describe an expression that might derive from a generic formal object. Well, OK, I just had a rather goofy idea. Does the following work (to replace the second sentence of 4.9(33): This evaluation is performed exactly, without performing Overflow_Checks, unless the expression is in an instance and the expression is non-static in the generic. This describes operationally the rule we want. Does this work?? **************************************************************** From: Tucker Taft Sent: Thursday, September 20, 2001 10:11 AM We should look at paragraphs 33-37 together. 37 already talks about generic formal types. It would seem we should somehow work the generic formal object and generic formal type rules together. On the other hand, are we presuming that the *spec* of an instance is shared? I thought that was essentially impossible in Ada 95. Why can't the spec of an instance use exact evaluation? **************************************************************** From: Pascal Leroy Sent: Thursday, September 20, 2001 2:00 PM I was puzzled by this too. Evidently we don't want to require exact evaluation in bodies, but in specs it seems innocuous. Sharing specs in Ada 95 is close to impossible, because of all the rechecking that has to be done on instances. This is one of the reasons why we got rid of shared generics, btw: we used to share specs in Ada 83, and this model was hopelessly broken by Ada 95. **************************************************************** From: Randy Brukardt Sent: Thursday, September 20, 2001 8:48 PM Tucker said: On the other hand, are we presuming that the *spec* of an instance is shared? I thought that was essentially impossible in Ada 95. Why can't the spec of an instance use exact evaluation? Pascal said: I was puzzled by this too. Evidently we don't want to require exact evaluation in bodies, but in specs it seems innocuous. Sharing specs in Ada 95 is close to impossible, because of all the rechecking that has to be done on instances. This is one of the reasons why we got rid of shared generics, btw: we used to share specs in Ada 83, and this model was hopelessly broken by Ada 95. And I reply: Rechecking is a red herring; what determines whether or not something can be shared is the code generation. And clearly there is no need to worry about the code generated if the instantiation will be illegal anyway. So that isn't a reason that generic specs cannot be shared. Indeed, you pretty much have to share specs in order to (always) share bodies; the data layout of the spec has to be the same for every instantiation, or the code to implement the body is laughable. That means that the majority of the elaboration code is also always the same: so why not share it? What we do for those few rules where "assume-the-best" has a code generation impact is to treat the item as a "hidden" generic formal. For instance, for tagged types declared in the specification of a generic unit, we generate a tag at instantiation time, then pass it as a generic formal to the generic unit. My objection was to adding another case where this hoop-jumping was necessary. However, that is moot. I realized on the way home last night that the rule I proposed was wrong: it would poison outside expressions by eliminating the requirement that their evaluation be exact. Thus the rule has to say "instance body". Indeed, Janus/Ada does use exact evaluation of static expressions in an instance spec -- but the result of that evaluation is not available in the generic. (Oddly, it only does so for integer types; perhaps to avoid the pathologies of exact evaluation for float types.) Generally, it doesn't matter: you'll get the same answer either way. I don't think this is a particular hardship, as I think any program that could tell the difference is a pathology, and I don't think that the ACATS will be testing it. :-) Janus/Ada has always behaved this way (back to Ada 83) and I don't think that anyone ever has complained. In the absence of a complaint backed up by $$$, it's likely to continue to behave that way. Tucker said: We should look at paragraphs 33-37 together. 37 already talks about generic formal types. It would seem we should somehow work the generic formal object and generic formal type rules together. And I respond: I don't see this. The formal type rule only applies to paragraphs 35 and 36, and always applies. While the formal object rules applies to all of paragraphs 33 to 36, but only in an instance body. Trying to merge them would seem to either require a significant change to the formal type rules (and they're not broken!), or some really convoluted wording. A safer alternative to my previous wording would be something like: If a static expression is in an instance body and the expression is non-static in the generic body, then none of the legality rules for static expressions apply in the instance. AARM Ramification Annotation: This means, among other things, that exact evaluation is not required for these expressions. Note that any rules which require a static expression must have been checked when the generic body was compiled, and would have made the body illegal for any expressions which trigger this rule, so the fact that these would not be checked in the instance is irrelevant. (All legality rules involving static expressions not found in 4.9 are those that require some expression to be static.) AARM Discussion Annotation: Such expressions depend on generic formal object parameters. In order to allow generic sharing, we do not want to require the evaluation of such expressions when the generic is instantiated (as this would introduce a dependence on the body). Is this better?? **************************************************************** From: Randy Brukardt Sent: Thursday, September 20, 2001 8:50 PM Oops, this is still slightly wrong. Try: If a static expression is in an instance body and the expression is non-static in the generic body, then none of the legality rules for static expressions apply to the expression in the instance. ****************************************************************