Version 1.1 of ai05s/ai05-0236-1.txt

Unformatted version of ai05s/ai05-0236-1.txt version 1.1
Other versions for file ai05s/ai05-0236-1.txt

!standard 10.2.1(10/2)          11-01-26 AI05-0236-1/01
!standard 10.2.1(10.1/2)
!standard 10.2.1(11.1/2)
!standard 10.2.1(11.2/2)
!standard 10.2.1(11.4/2)
!standard 10.2.1(11.8/2)
!class binding interpretation 11-01-26
!status work item 11-01-26
!status received 10-10-28
!priority Medium
!difficulty Easy
!qualifier Omission
!subject Additional Problem with preelaborated generics
!summary
!question
Consider:
generic type T is range <>; package G is pragma Preelaborate; end;
package body G is C : constant T := T'First; end G;
AI05-0028-1 claimed that this is illegal by existing rules, but there doesn't seem to be any way to prove that.
10.2.1(10.2/2) defines that a generic body is preelaborable only if its elaboration does not perform any of the actions listed in 10.2.1(5-9/3) assuming that the actual for each formal is nonstatic.
However I don't see any language that makes the constant declaration in question illegal even if T is non-static. None of the clauses listed under 10.2.1(5) apply:
* there's no statement in sight (6)
* there's no function call either (7)
* there's no object name that is evaluated (8) -- the only evaluated thing is the attribute reference T'First, and T'First is not the name of an object
* there's no default initialized object (9/3)
So why is this illegal? (Dunno.)
!recommendation
(See Summary.)
!wording
!discussion
The problem appears to be much more pervasive than noted in the question. By the logic of the question, none of the following constants appear to be illegal:
generic type T is range <>; type Stringy is array (T range <>) of Character; package G is pragma Preelaborate; end;
package body G is -- Attributes: C1 : constant T := T'First; C2 : constant Boolean := T'Last < 10; subtype S1 is Stringy(1..T'Last); C3 : constant S1 := (others => ' '); -- Membership: C4 : constant Boolean := 2 in T; -- Subtypes: C5 : constant Stringy(T) := (others => ' '); subtype S2 is Stringy(T); -- Aggregates: C6 : constant Stringy := (T => ' '); -- Range checks: C7 : constant T := 1; end G;
The root of the problem is that the rules 10.2.1(5-9) were designed assuming that non-static subtypes could be not be declared: any attempt to do so would violate one of the other rules.
But then we went and built rules that completely violate that assumption.
It's not clear how to fix this without making lots of things illegal that currently are legal. The easy solution:
* The elaboration or evaluation of a construct that includes a name denoting a non-static subtype.
would pretty much prevent any use of generic formals other than inside of subprograms in a preelaborated generic. Moreover, it would prevent declaration of types involving components of formal types, which seems like going too far.
Enumerating the problem cases seem to lead us to a warren of holes.
Finally, there is the option of doing nothing. None of the examples above trigger C.4(2-11), so the fact that they are dynamic is pretty much irrelevant.
--!corrigendum 10.2.1(9/2)
!ACATS test
Better be some.
!appendix

From: Thomas Quinot
Date: Thursday, October 28, 2010  10:01 AM

I am back with more worries regarding preelaborable initialization.

The discussion in AI05-028 addresses, among others, the following
question:

> !question
>
> 3 - I can't find a rule that would make the following illegal:
>
> 	generic
> 	   type T is range <>;
> 	package G is
> 	   pragma Preelaborate;
> 	end;
>
> 	package body G is
> 	   C : constant T := T'First;
> 	end G;

> For question 3, the petitioner seems confused, as the example is illegal by 10.2.1(10.2/2).

I don't understand this claim. 10.2.1(10.2/2) defines that a generic body is
preelaborable only if its elaboration does not perform any of the actions listed
in 10.2.1(5-9/3) *assuming that the actual for each formal is nonstatic*.

However I don't see any language that makes the constant declaration in question
non static even if T is non-static. None of the clauses listed under 10.2.1(5)
apply:
  * there's no statement in sight (6)
  * there's no function call either (7)
  * there's no object name that is evaluated (8) --
    the only evaluated thing is the attribute reference T'First,
    and T'First is not the name of an object
  * there's no default initialized object (9/3)

Shouldn't 10.2.1(8) have a provision for attribute references (in addition to
"primaries that are names of objects"), or do we need an additional item
(9.1/3)?

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

From: Adam Beneschan
Date: Thursday, October 18, 2010  10:49 AM

For what it's worth, I agree with Thomas.  (At first I thought that 'First would
be considered a subprogram call, but 'First isn't a function---although some
other attributes are.)

Adding a provision for attribute references may not quite be enough:

    generic
       type T is (<>);
    package G is
       pragma Preelaborate;
    end;

    package body G is
       type Arr is array (T range <>) of Integer;
       Zero : constant Arr := (T => 0);
    end;

No attribute references here, but (because the aggregate implicitly needs
T'First and T'Last) this shouldn't be preelaborable either, I think...?

On the other hand, not all attribute references cause a problem---certainly
'Base wouldn't, and some attributes like 'Modulus, 'Digits, 'Delta are always
static even if they are applied to non-static subtypes, so we wouldn't
necessarily want those to preclude generic bodies from being preelaborable.

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

From: Adam Beneschan
Date: Thursday, October 28, 2010  11:41 AM

After looking into this a bit further, here's what I would suggest:

Add these bullet points to the list in 10.2.1(6-9):

* The evaluation of an attribute_reference whose prefix is a nonstatic
  subtype and whose attribute_designator is First, Last, Length,
  Range, or an attribute_designator not defined by the language.

* The elaboration of a nonstatic subtype used as a discrete_range, or
  as a discrete_subtype_definition in a constrained_array_definition.

I'm not totally sure about that "not defined by the language" bit, but I'd worry
that there *could* be an implementation-defined attribute whose value would be
nonstatic for a nonstatic subtype.  An alternative may be

* The evaluation of an attribute_reference that denotes a saclar
  value, and whose prefix denotes a nonstatic scalar subtype.

which would be broader than necessary, since it would disallow some things like
'Modulus, but at least we'd be sure we didn't let anything slip through.

In the absence of generics, I don't think it would be necessary to include these
in the 10.2.1(6-9) list (you couldn't even have a reference [outside of a
subprogram] to a nonstatic subtype in a preelaborable package, right?), but for
the sake of 10.2.1(10) it may be necessary to include them.

* * * *

One other thing I noticed, while looking into this (note: this belongs in the
let's-read-the-RM-hyperliterally-and-see-what-happens class of problems):
10.2.1(8) says you can't have "the evaluation of a primary that is a name of an
object, unless the name is a static expression etc.".  What happens with a value
conversion?  Now the _primary_ is a _name_ but it is not the _name_ of an object
(it isn't listed in 3.3), but the reference to the object is not in a place
where it would be a _primary_.  Do type conversions need to be mentioned
specifically in 10.2.1(8)?

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

From: Thomas Quinot
Date: Thursday, October 28, 2010  11:53 AM

> * The evaluation of an attribute_reference whose prefix is a nonstatic
>   subtype and whose attribute_designator is First, Last, Length,
>   Range, or an attribute_designator not defined by the language.

Actually I think whether or not a given implementation defined attribute is
acceptable for preelaborable initialization should be a (documented)
implementation defined characteristic.

> * The elaboration of a nonstatic subtype used as a discrete_range, or
>   as a discrete_subtype_definition in a constrained_array_definition.

I think this needs rewording, the non-static subtype is elaborated as part of
the effect of elaboration of its declaration, not when it is used in a discrete
range or discrete subtype definition...

> One other thing I noticed, while looking into this (note: this belongs
> in the let's-read-the-RM-hyperliterally-and-see-what-happens class of
> problems): 10.2.1(8) says you can't have "the evaluation of a primary
> that is a name of an object, unless the name is a static expression
> etc.".  What happens with a value conversion?  Now the _primary_ is a
> _name_ but it is not the _name_ of an object (it isn't listed in 3.3),
> but the reference to the object is not in a place where it would be a
> _primary_.  Do type conversions need to be mentioned specifically in
> 10.2.1(8)?

Yes indeed value conversions might need mentioning...

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

From: Adam Beneschan
Date: Thursday, October 28, 2010  12:03 PM

> > * The elaboration of a nonstatic subtype used as a discrete_range, or
> >   as a discrete_subtype_definition in a constrained_array_definition.
>
> I think this needs rewording, the non-static subtype is elaborated as
> part of the effect of elaboration of its declaration, not when it is
> used in a discrete range or discrete subtype definition...

I'm not sure that's correct, looking at the wording of 3.6.1(8) and 3.2.2(9).
Those paragraphs (among others) are what I was looking at when I came up with my
suggested wording.  However, I'm not the expert on this.  I'm sure some of the
ARG members will know for sure whether the wording is correct or needs tweaking.

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

From: Randy Brukardt
Date: Thursday, October 28, 2010  10:32 PM

I don't understand your question. The language says that you must presume T is a
nonstatic subtype. That means by the definition of "static constant" in 4.9 that
C is not a static constant, because a static constant must have a static
subtype. QED.

It's not only the rules in 10.2.1 that apply, of course.

(One also wonders if anyone could care, given that the constant is dead - there
is no use; any use would violate the rules. Since it is practically impossible
to avoid code generation for the elaboration of a preelaborable unit, the fact
that might occur (before optimization) seems irrelevant. Since it is dead, after
optimization it could be gone.)

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

From: Thomas Quinot
Date: Friday, October 29, 2010  7:29 AM

> I don't understand your question.

Let me clarify.

> The language says that you must presume T is a nonstatic subtype. That
> means by the definition of "static constant" in
> 4.9 that C is not a static constant, because a static constant must
> have a static subtype. QED.

Right, this proves that C is not a static constant, and I think everyone agrees
about that. The question is: is this declaration *preelaborable*?

I think the intent is clearly that a non-static constant cannot be
preelaborable, but I cannot find any language in the RM that indeed makes it
non-preelaborable.

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

From: Thomas Quinot
Date: Friday, October 29, 2010   7:37 AM

> > > * The elaboration of a nonstatic subtype used as a discrete_range, or
> > >   as a discrete_subtype_definition in a constrained_array_definition.
> >
> > I think this needs rewording, the non-static subtype is elaborated
> > as part of the effect of elaboration of its declaration, not when it
> > is used in a discrete range or discrete subtype definition...
>
> I'm not sure that's correct, looking at the wording of 3.6.1(8) and
> 3.2.2(9).  Those paragraphs (among others) are what I was looking at
> when I came up with my suggested wording.  However, I'm not the expert
> on this.  I'm sure some of the ARG members will know for sure whether
> the wording is correct or needs tweaking.

Umm, OK, I see, indeed it's a bit more complicated than I anticipated.
I'd reorganize the clause as:
  "the elaboration of a discrete_range or discrete_subtype definition
   in a constrained_array_definition, if it does not define a static
   subtype".

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

From: Adam Beneschan
Date: Friday, October 29, 2010  10:42 AM

> I don't understand your question. The language says that you must
> presume T is a nonstatic subtype. That means by the definition of
> "static constant" in
> 4.9 that C is not a static constant, because a static constant must
> have a static subtype. QED.

The point Thomas was making (and reiterated in his response to the
above) is that yes, C is not a static constant, but nothing in the rules says
that a non-static constant makes a construct non-preelaborable.  10.2.1 says,
"An elaborable construct is preelaborable unless ..." and then gives a list of
things that would make the construct non-preelaborable.  The presence of a
non-static constant isn't on the list.  (I'm still under the impression that, in
the absence of generics, there's no way to refer to a non-static constant in a
preelaborable construct because some *other* rule would necessarily be violated.
Perhaps that's why there's nothing about non-static constants explicitly in this
list.  But it doesn't work when generics are involved.)

> It's not only the rules in 10.2.1 that apply, of course.
>
> (One also wonders if anyone could care, given that the constant is
> dead - there is no use; any use would violate the rules. Since it is
> practically impossible to avoid code generation for the elaboration of
> a preelaborable unit, the fact that might occur (before optimization) seems irrelevant.
> Since it is dead, after optimization it could be gone.)

The constant could still be used inside a procedure, right?  (I don't think
Pascal's example was intended to be a complete example; if it is, it won't
compile anyway because G does not require a body!)  Of course, where a scalar
constant is involved, and its only use is inside procedures, it probably doesn't
effect preelaborability anyway---the code that uses that constant wouldn't need
to pull it from some global memory location.  But T'First could still be used in
a large aggregate:

   package body G is
       type Current_Index_Arr is array (1 .. 100) of T;
       Current_Indexes : Current_Index_Arr := (others => T'First);
       ... subprogram bodies
   end G;

And, unless I've totally lost the plot, we'd want an aggregate like that to make
the generic body non-preelaborable, but there's still nothing about it that
performs any of the prohibited actions in 10.2.1(6-9).

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

From: Randy Brukardt
Date: Friday, November 12, 2010  5:10 PM

> I think the intent is clearly that a non-static constant cannot be
> preelaborable, but I cannot find any language in the RM that indeed
> makes it non-preelaborable.

I see. [I just remembered that I forgot to answer this one after I read it on my
phone days ago.]

One answer is that it doesn't really matter: preelaboration doesn't necessarily
have anything to do with code generation: it's just a restricted form of
package. C.4 only requires static constants to not generate code, and since this
is not a static constant, it does not apply anyway. Moreover, it would be
impossible for a compiler on most targets to actually avoid generating code for
all elaboration of a preelaborated packages. (One example is the initialization
of the mutual exclusion lock or other mechanism for protected objects; that's
going to require a system call on many targets.) Besides, any same
implementation will avoid generation of extra elaboration code whether or not
the Preelaboration category is used. For a code-shared implementation like
Janus/Ada, preelaboration of an instance is totally meaningless, and that of a
generic unit has almost no impact. The net effect for this example is that the
non-static declaration might sometimes generate code (even for a template
implementation), and that is allowed by the existing rules. BFD.

But I can understand that this is not very satisfying. The problem here is that
this is *much* more pervasive than noted in your original question, and I can't
think of any rule that would reasonably cover it. Here are some of the cases
that cause trouble:

       generic
          type T is range <>;
          type Stringy is array (T range <>) of Character;
       package G is
          pragma Preelaborate;
       end;

       package body G is
          -- Attributes:
          C1 : constant T := T'First;
          C2 : constant Boolean := T'Last < 10;
          subtype S1 is Stringy(1..T'Last);
          C3 : constant S1 := (others => ' ');
          -- Membership:
          C4 : constant Boolean := 2 in T;
          -- Subtypes:
          C5 : constant Stringy(T) := (others => ' ');
          subtype S2 is Stringy(T);
          -- Aggregates:
          C6 : constant Stringy := (T => ' ');
          -- Range checks:
          C7 : constant T := 1;
       end G;

None of these violate any of 10.2.1(5-9), so far as I can tell. These are all
non-static constants, but we don't want to allow the subtype declarations either
(at least if we are worrying about code generation). And I haven't made any
attempt to think about anything other than integer formal types; there are
probably lots of ways to cause trouble with other kinds of formals.

One could imagine a rule disallowing the evaluation of an expressions containing
the name of a non-static subtype (as opposed to elaboration of such a name), but
I'm neither sure that it covers all the cases nor that it doesn't cover too
much.

As such, I wonder about even trying to fix this. It seems to me that doing so
will pretty much make it impossible to write a preelaborated generic that does
anything (much stronger rules than the non-generic equivalent). And, as
previously pointed out, there is no real conflict with the rules in C.4.

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

From: Randy Brukardt
Date: Wednesday, January 26, 2011  11:19 PM

> One other thing I noticed, while looking into this (note:
> this belongs in the
> let's-read-the-RM-hyperliterally-and-see-what-happens class of
> problems): 10.2.1(8) says you can't have "the evaluation of a primary
> that is a name of an object, unless the name is a static expression
> etc.".  What happens with a value conversion?  Now the _primary_ is a
> _name_ but it is not the _name_ of an object (it isn't listed in 3.3),
> but the reference to the object is not in a place where it would be a
> _primary_.  Do type conversions need to be mentioned specifically in
> 10.2.1(8)?

I don't think this is right. We're talking about a case like
"Natural(My_Function)", right?

4.6(7) says that the operand of a value conversion is interpreted as an
Expression. That's "My_Function" in this case. "My_Function" is a Name; to get
to Name from Expression in the Ada grammar, we have to pass through "Primary".
So 10.2.1(8) *does* apply to a value conversion of the Name of an object.

If we try to use an operator to prevent going to the Name directly, then the
operands end up passing through Primary, and again the rule applies.

So I don't think there is any problem here (unless you can provide an example I
haven't thought of).

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


Questions? Ask the ACAA Technical Agent