Version 1.3 of ais/ai-00269.txt

Unformatted version of ais/ai-00269.txt version 1.3
Other versions for file ais/ai-00269.txt

!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)
Insert after the paragraph:
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).
the new paragraph:
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:
> <<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).
> >>
>
> 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

<<Yes, obviously the instantiation is illegal because of division by zero>>

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

<<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...">>

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

<<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.>>

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

<<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.>>

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 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!!)>>

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

<<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).>>

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<static constant> is a constant view declared by a full constant
> declaration, an @fa<object_renaming_declaration> with a static nominal
> subtype, or generic formal object of mode @b<in> 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<string_literal> 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.

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


Questions? Ask the ACAA Technical Agent