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

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

!standard 10.2.1(10/2)          11-03-16 AI05-0236-1/02
!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 confirmation 11-03-16
!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 is this legal? (Yes.)
!response
After much discussion, it was decided that these kinds of issues are not worth fixing. Yes, this means that some preelaborated units will need to execute code during elaboration. But this doesn't cause any logical problems.
In any case, fixing these kinds of issues would necessarily by incompatible, so we decided to live with these somewhat-questionable rules.
Note that none of the examples trigger C.4(2-11), so the fact that they are dynamic is pretty much irrelevant.
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 of adding:
* The elaboration or evaluation of a construct that includes a name denoting a non-static subtype.
to 10.2.1(5-9) 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.
!ACATS test
None needed.
!ASIS
No change, so no ASIS impact.
!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).

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

From: Adam Beneschan
Date: Thursday, January 27, 2011  9:50 AM

You're right, I missed that.  Thanks.

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

From: Adam Beneschan
Date: Monday, February 21, 2011  7:44 PM

!topic Preelaborable_Initialization inconsistency?
!reference 10.2.1(11.3/2)
!from Adam Beneschan 11-02-21
!discussion

I realize this is kind of late for anything to be done to Ada 2012; but I note
that AI05-236 is still listed as a "work item" on ada-auth.org, so maybe this
should be thrown into this AI if it's simple to fix (if a fix is needed)...

I'm trying to figure out whether this example is intended to be legal:

    generic
        type Index_Type is range <>;
    package Gen_Pack is
        pragma Preelaborate;
        C : constant Index_Type := Index_Type'First;

        type T1 is tagged private;
        pragma Preelaborable_Initialization (T1);
    private
        type T1 is tagged record
            X : Index_Type := Index_Type'First;  --(A)
        end record;
    end Gen_Pack;

My understanding is that the declaration of C is legal, even though the package
is declared with Preelaborate and C's initial expression is a nonstatic
expression, since the elaboration of the generic specification doesn't actually
evaluate anything.  (An instance of Gen_Pack may be illegal depending on the
actual type for Index_Type, but that's not my concern here.)

I'm less clear on line (A), though.  For the Preelaborable_Initialization pragma
to be legal, the full view has to have preelaborable initialization, which means
that the components all have to have preelaborable initialization.
10.2.1(11.3/2) says that a component with a default expression has preelaborable
initialization if the expression's execution doesn't perform any actions
prohibited in preelaborable constructs.

This is where I'm getting hung up, because to me the expression's execution
*does* perform an operation that's prohibited in preelaborable constructs, i.e.
evaluating a nonstatic expression Index_Type'First.  The way I interpret the
rules, C's initial expression is also prohibited in preelaborable constructs,
but that doesn't make C illegal because C isn't actually elaborated.  But the
way 10.2.1(11.3/2) is worded, the fact that nothing is elaborated doesn't
matter.

I'm guessing that this isn't the intent; i.e. that in a generic package
specification, X is legal just as C is (but that X could make the
Preelaborable_Initialization pragma illegal in a particular instance of the
generic).  I'm not sure the wording is adequate to reflect this intent, though.
(If others agree that the wording needs clarification, this could be a case
where a To Be Honest paragraph in the AARM is sufficient.)

But I'd still like confirmation from someone that the above source is supposed
to be legal, because I'm looking into a bug report that involves this.  (No, I'm
not making a last-minute push to find errors in the RM before the deadline.
This one arises from a real issue.)

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

From: Randy Brukardt
Date: Monday, February 28, 2011  12:43 AM

...
> I realize this is kind of late for anything to be done to Ada 2012;
> but I note that AI05-236 is still listed as a "work item" on
> ada-auth.org, so maybe this should be thrown into this AI if it's
> simple to fix (if a fix is needed)...

Well, as usual your timing is perfect (NOT): the ARG meeting ended the day
before you sent this.

We essentially decided that it wasn't worth fixing the problem noted in
AI05-0236-1. The only preelaborable things that shouldn't generate code are
listed in C.4, and these aren't (we think) incompatible with the bizarre cases
in AI05-0236-1. (We also noted that a fix would be incompatible.)

But...

> I'm trying to figure out whether this example is intended to be legal:
>
>     generic
>         type Index_Type is range <>;
>     package Gen_Pack is
>         pragma Preelaborate;
>         C : constant Index_Type := Index_Type'First;
>
>         type T1 is tagged private;
>         pragma Preelaborable_Initialization (T1);
>     private
>         type T1 is tagged record
>             X : Index_Type := Index_Type'First;  --(A)
>         end record;
>     end Gen_Pack;
>
> My understanding is that the declaration of C is legal, even though
> the package is declared with Preelaborate and C's initial expression
> is a nonstatic expression, since the elaboration of the generic
> specification doesn't actually evaluate anything.  (An instance of
> Gen_Pack may be illegal depending on the actual type for Index_Type,
> but that's not my concern here.)

Right, although this is a language bug that isn't worth fixing, not a "feature".

> I'm less clear on line (A), though.  For the
> Preelaborable_Initialization pragma to be legal, the full view has to
> have preelaborable initialization, which means that the components all
> have to have preelaborable initialization.  10.2.1(11.3/2) says that a
> component with a default expression has preelaborable initialization
> if the expression's execution doesn't perform any actions prohibited
> in preelaborable constructs.

I don't see this. This is identical to the expression in the original
AI05-0236-1 question (and the reason that C is legal). The problem is that
Index_Type'First is not the name of an object (it is a value), so none of the
rules of 10.2.1(5-9/2) are violated. So there is no illegality here.

Worse, I don't see any reason that this is true in an instance, either, no
matter what the actual type is.

That's bad, because this subtype would be lying about the
"preelaborable_initialization" property in an instance with a dynamic actual for
Index_Type. OTOH, again there is no guarantee about no code being generated for
such types (as described in C.4), so there is no formal problem with this.

...
> I'm guessing that this isn't the intent;

Please don't guess about the intent; there is no intent here other than that we
don't want to mess with this problem at all. :-)

...
> But I'd still like confirmation from someone that the above source is
> supposed to be legal, because I'm looking into a bug report that
> involves this.  (No, I'm not making a last-minute push to find errors
> in the RM before the deadline.  This one arises from a real issue.)

Nice to hear that your customers find RM corner cases just like you do. :-)

The ARG adopted the following resolution at the end of the recent meeting:

"Thanks to Adam Beneschan for providing problems whose complexity is in inverse
proportion to their importance."

[I suspect that you have been getting "credit" for some questions that you
didn't raise...but some of the "best" ones definitely are yours - particularly
AI05-0115-1.]

I admit that there are times that I'm glad that you don't come to ARG meetings.
I suspect that putting you and Steve Baird in the same room would cause
quadratic multiplying of bizarre language cases to the point that the heads of
some ARG members would explode! ;-)

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

From: Randy Brukardt
Date: Tuesday, March 15, 2011  4:37 PM

> I'm happy with saying, "Sorry, that message came in too late, if it's
> a real bug, maybe we'll fix it for Ada 2020."

That's a possibility.

> You've been pounding your shoe on the table about keeping to the Ada
> 2012 schedule, and dealing with every little thing doesn't help with
> that.  ;-)

True, but in this case, we decided not to deal with the bug (ever), and Adam has
shown another interesting consequence of that (preelaborable_initialization is a
lie) that we hadn't considered. I'm not sure that there is a real problem
(everything is self consistent, just meaningless), but I wanted someone to think
about it before we round-filed the problem.

If we think we *do* need a fix, then we probably should take this entire AI off
the table now, in order to keep to the schedule (the original AI also was too
late in that it wasn't opened until after the June 2010 deadline, so we're under
no obligation to fix it now). But of course as a bug, we don't want to lose it
completely.

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

From: Bob Duff
Date: Wednesday, March 16, 2011  4:58 PM

OK, I read the message in question, and decided that it's in the same category
as the other stuff in this AI -- the rules are kind of messed up, but there's no
actual problem that NEEDS to be fixed.  I've included a new version of

    AI05-0236-1, Additional Problem with preelaborated generics

below, written as a !confirmation.  [This is version /02 of the AI - Editor.]
Randy, I suggest you include the email mentioned above in the !appendix, so it
doesn't get lost, but we take no further action on these issues.

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


Questions? Ask the ACAA Technical Agent