Version 1.2 of ai12s/ai12-0232-1.txt

Unformatted version of ai12s/ai12-0232-1.txt version 1.2
Other versions for file ai12s/ai12-0232-1.txt

!standard 10.2.1(9/3)          17-06-08 AI12-0232-1/01
!standard 10.2.1(15.6/3)
!class binding interpretation 17-06-08
!status work item 17-06-08
!status received 17-06-08
!priority Low
!difficulty Medium
!qualifier Omission
!subject Rules for pure generic bodies
!summary
** TBD.
!question
10.2.1(16) (which was replaced, as part of ai95-0366) says:
A pure library_item is a preelaborable library_item that does not contain the declaration of any variable or named access type, except within a subprogram, generic subprogram, task unit, or protected unit.
However, the rewording doesn't seem to have the same effect.
In particular, 10.2.1(15.1/3-15.5/3) give rules for a pure compilation unit. 10.2.1(15.6/3) gives a special rule for generic bodies.
But nothing seems to apply to nested generic bodies. For a generic in a package or generic package, it seems that some rule ought to apply. Is there a rule missing? (Yes.)
!recommendation
(See Summary.)
!wording
** TBD.
!discussion
E-mail discussion suggests that there is a similar problem with Preelaboration. The form of the preelaboration wording goes back to Ada 95 (it has not been substantially changed). The main difference is that it talks about "elaborable constructs" rather than "compilation units".
The author guesses that most readers quickly learn to apply 10.2.1(5-9/2) recursively (as a practical matter, it has to be applied that way when reading code or writing a compiler; it's necessary to look inside of every nested construct with non-trivial elaboration). It's possible to read those rules as applying through some sort of magic, which would leave the question about generic bodies unanswered. But that doesn't make much sense (and no actual compilers seem to operate that way).
Probably the best fix here is to explicitly say that 10.2.1(5-9/2) is recursive, by adding after 10.2.1(9/3):
* The elaboration of any elaborable construct that is not preelaborable.
Then the existing generic body rule clearly applies (and any future rules on new kinds of entities will apply as well).
---
The Ada 95 wording clearly bans variables in generic specifications. The current Pure wording does not. AI95-0366-1 seems to imply this is on purpose; AI05-0035-1 reverses that in the text, but not in the actual wording chosen.
Clearly, a generic specification that contains a variable declaration could never, ever be instantiated as Pure. OTOH, the existing 10.2.1(15.6/3) rule really serves as an assume-the-worst rule; we can recheck in the instance for the specification.
So what do we want to do? If we really want to ensure that a pure generic unit can be instantiated as Pure, then we need to enforce at least some of the rules in a generic specification. ** The author has no idea what to do here.
** What fix to apply to for the original question depends on the answer to this question, so the author is punting.
!ASIS
No ASIS effect.
!ACATS test
ACATS B-Tests ought to check that Pure (and Preelaborate?) rules are applied to nested generics as required.
!appendix

From: Tucker Taft
Sent: Saturday, May 13, 2017  4:35 PM

The RM rules in 10.2.1 for what makes a generic package body "pure" seem
inadequate to ensure that an instance of such a generic, when given suitable
actuals, can be pure.  The problem is there is no mention of nested generic
bodies.  Here are the relevant rules from 10.2.1:

(15.1/3) A pure compilation unit is a preelaborable compilation unit whose
elaboration does not perform any of the following actions:

(15.2/2) * the elaboration of a variable declaration;

          ...

(15.6/3)  A generic body is pure only if elaboration of a corresponding instance
body would not perform any such actions presuming any composite formal types
have nonvisible components whose default initialization evaluates an allocator
of an access-to-variable type.

   ...

(17/3)   ... The declaration and body of a declared pure library unit, and all
subunits that are elaborated as part of elaborating the library unit, shall be
pure. ...

---

The above rules don't really indicate which generic bodies need to be pure.  If
a generic is nested inside a subprogram, presumably it doesn't need to be pure.
On the other hand, if a generic body is nested inside another generic body that
is required to be pure, must it also be pure?  I think the intent is yes, but
nowhere does it say that.

So I think we need to add something to the list of prohibited actions, such as:

  (15.5.1) * the elaboration of a generic body that is not pure;

This will ensure that a generic body nested in a generic body must pass the
rules for being pure, while a generic body nested in a subprogram has no such
requirement.

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

From: Randy Brukardt
Sent: Monday, May 15, 2017  7:37 PM

> The RM rules in 10.2.1 for what makes a generic package body "pure"
> seem inadequate to ensure that an instance of such a generic, when
> given suitable actuals, can be pure.  The problem is there is no
> mention of nested generic bodies.
...
> The above rules don't really indicate which generic bodies need to be
> pure.  If a generic is nested inside a subprogram, presumably it
> doesn't need to be pure. On the other hand, if a generic body is
> nested inside another generic body that is required to be pure, must
> it also be pure?  I think the intent is yes, but nowhere does it say
> that.

Why do you think the intent is "yes"? I don't (off-hand) see any need for that;
the nested generic body is not elaborated as part of the instance of the outer
body. We don't require anything else nested to be pure unless it is in fact
elaborated (as you acknowledge by mentioning the inside a subprogram case).

> So I think we need to add something to the list of prohibited actions,
> such as:
>
>   (15.5.1) * the elaboration of a generic body that is not pure;
>
> This will ensure that a generic body nested in a generic body must
> pass the rules for being pure, while a generic body nested in a
> subprogram has no such requirement.

Such a rule would be incompatible (uncertain if that would matter in practice,
but clearly the possibility makes the bar higher for a change). So I think you
need a strong case as to why that would be desirable. (Especially as the Pure
categorization is useless in practice and hopefully will be effectively replaced
in Ada 2020 by the Global aspect.)

Again, we have a case of a solution without an actual problem. I realize we all
do it, but given that we're trying hard to enforce that on outside suggestions,
we at least could try to provide some idea of what the problem is for our
in-house suggestions. (I don't mean to target Tuck on this one -- it's a
reminder to everyone.)

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

From: Tucker Taft
Sent: Monday, May 15, 2017  9:05 PM

...
> Why do you think the intent is "yes"? I don't (off-hand) see any need
> for that; the nested generic body is not elaborated as part of the
> instance of the outer body. We don't require anything else nested to
> be pure unless it is in fact elaborated (as you acknowledge by
> mentioning the inside a subprogram case).

Because if you don’t, I believe you have a contract violation.  Presumably the
point of the original rule about generic bodies was that if you instantiate such
the outer generic, you know just from looking at the actuals whether the
instance is pure.  But if we allow nested generic bodies to be impure, then in
fact you could be wrong.  E.g.:

   generic
   package Outer is
      pragma Pure(Outer);
      generic
      package Inner is
         procedure Dummy;
      end Inner;
   end Outer;

   package body Outer is
       function Complicated(S : String) return Integer is
       begin
            return Integer’Value(S);
       end Complicated;

       package body Inner is
           Evil_Global : Integer := Complicated(“12345”);
           procedure Dummy is begin null; end Dummy;
      end Inner;
   end Outer;


package Outer_Inst is new Outer;
pragma Pure(Outer_Inst);  —  Legal or not?

package Inner_Inst is new Outer_Inst.Inner; pragma Pure(Inner_Inst);  — Legal or
not?

>
>> So I think we need to add something to the list of prohibited
>> actions, such as:
>>
>>  (15.5.1) * the elaboration of a generic body that is not pure;
>>
>> This will ensure that a generic body nested in a generic body must
>> pass the rules for being pure, while a generic body nested in a
>> subprogram has no such requirement.
>
> Such a rule would be incompatible (uncertain if that would matter in
> practice, but clearly the possibility makes the bar higher for a
> change). So I think you need a strong case as to why that would be desirable.
> (Especially as the Pure categorization is useless in practice and
> hopefully will be effectively replaced in Ada 2020 by the Global
> aspect.)

See above.  I believe the Preelaborate() pragma has exactly the same problem.

> Again, we have a case of a solution without an actual problem. I
> realize we all do it, but given that we're trying hard to enforce that
> on outside suggestions, we at least could try to provide some idea of
> what the problem is for our in-house suggestions. (I don't mean to
> target Tuck on this one -- it's a reminder to everyone.)

I would also claim that the current rule about what it means for a generic body
to be pure is only relevant if the generic is itself a library unit.  For a
generic package nested in a pure library package, there is nothing that links
the definition of what a “pure” generic body is to the rules for what it means
for the enclosing library package to be pure.  So I believe the suggested rule
is needed even just to make it a requirement that a generic body nested in a
non-generic declared-pure library package is pure.

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

From: Randy Brukardt
Sent: Tuesday, May 16, 2017  5:15 PM

...
> > Why do you think the intent is "yes"? I don't (off-hand) see any
> > need for that; the nested generic body is not elaborated as part of
> > the instance of the outer body. We don't require anything else
> > nested to be pure unless it is in fact elaborated (as you
> > acknowledge by mentioning the inside a subprogram case).
>
> Because if you don't, I believe you have a contract violation.
> Presumably the point of the original rule about generic bodies was
> that if you instantiate such the outer generic, you know just from
> looking at the actuals whether the instance is pure.  But if we allow
> nested generic bodies to be impure, then in fact you could be wrong.
> E.g.:
>
>    generic
>    package Outer is
>       pragma Pure(Outer);
>       generic
>       package Inner is
>          procedure Dummy;
>       end Inner;
>    end Outer;
>
>    package body Outer is
>        function Complicated(S : String) return Integer is
>        begin
>             return Integer'Value(S);
>        end Complicated;
>
>        package body Inner is
>            Evil_Global : Integer := Complicated("12345");
>            procedure Dummy is begin null; end Dummy;
>       end Inner;
>    end Outer;

I might be dense, but I don't see any problem with this. (***)

> package Outer_Inst is new Outer;
> pragma Pure(Outer_Inst);  -  Legal or not?

Sure, the inner generic isn't elaborated as part of this, so there is no
problem. (And you don't re-enforce Legality Rules in an instance body, so any
rules about the body are moot.)

> package Inner_Inst is new Outer_Inst.Inner; pragma Pure(Inner_Inst);
> - Legal or not?

No, this isn't declared Pure.

The only problem I see here is that the only way to make an inner generic
declared pure is to make it a child generic instead. That's a bit odd but not a
big deal. (It could be easily fixed by allowing aspect Pure on a nested generic
unit -- a better semantics anyway -- but that would take quite a bit of
wording.)

> >> So I think we need to add something to the list of prohibited
> >> actions, such as:
> >>
> >>  (15.5.1) * the elaboration of a generic body that is not pure;
> >>
> >> This will ensure that a generic body nested in a generic body must
> >> pass the rules for being pure, while a generic body nested in a
> >> subprogram has no such requirement.
> >
> > Such a rule would be incompatible (uncertain if that would matter in
> > practice, but clearly the possibility makes the bar higher for a
> > change). So I think you need a strong case as to why that would be desirable.
> > (Especially as the Pure categorization is useless in practice and
> > hopefully will be effectively replaced in Ada 2020 by the Global
> > aspect.)
>
> See above.  I believe the Preelaborate() pragma has exactly the same
> problem.

I don't think so, because 10.2.1(10/2-10.4/2) applies to all generic bodies. (It
definitely doesn't have any restriction to library level bodies). It's an
assume-the-worst rule -- and it really does assume-the-worst. It appears that
the problem that you are worried about is unique to aspect Pure, and only for
properties that are unique to that aspect.

I do think we need to find out what existing compilers do with such generic
units, because the suggested rule has the possibility of being *very*
incompatible with existing code. If compilers are enforcing rules similar to the
suggested one already, then there may not be a real problem, but if they aren't,
we're at risk of breaking chunks of real code that might be very hard to fix
(especially for Pure).

Could you create such a test program, or do I have to do everything? :-)

> > Again, we have a case of a solution without an actual problem. I
> > realize we all do it, but given that we're trying hard to enforce
> > that on outside suggestions, we at least could try to provide some
> > idea of what the problem is for our in-house suggestions. (I don't
> > mean to target Tuck on this one -- it's a reminder to everyone.)
>
> I would also claim that the current rule about what it means for a
> generic body to be pure is only relevant if the generic is itself a
> library unit.  For a generic package nested in a pure library package,
> there is nothing that links the definition of what a "pure" generic
> body is to the rules for what it means for the enclosing library
> package to be pure.
> So I believe the suggested rule is needed even just to make it a
> requirement that a generic body nested in a non-generic declared-pure
> library package is pure.

I think it's fairly clear that nested generic units are never Pure or
Preelaborated (with the current rules). That's consistent (as noted previously)
but one can argue that it isn't a good idea.

If there is a compatibility problem, I think I'd rather fix the root problem
(nested generics aren't cateogizable) than add a hack that could break a lot of
existing code. But neither solution is particularly pretty.

(***) Hmmm, it appears from 10.2.1(10/2), the generic you declare above is
illegal. The call of Complicated is a "call to a subprogram" that is not one of
the things listed in 10.2.1(7/5-7.4/5), and it is executed during the
elaboration of an instance of Inner. So Inner is not preelaborable. So what's
the problem? All of the declarations of a preelaborated unit have to be
preelaborable (that includes the subprograms, but their contents don't matter as
the elaboration of a subprogram does nothing other than set the elaborated
flag).

You appear to be reading the rules as if preelaboration only applies to the
top-level unit. But that doesn't make any sense, since it would allow the
elaboration of various nested declarations that happen to be units (such as
tasks, PTs, etc.) to do bad things. That surely can't be intended. And
10.2.1(10/2) clearly adds to the normal rules; it applies to any generic body
that is elaborated.

I could see a bit of clarification in the AARM (if you can read the rules wrong,
they're obviously not as clear as they should be). We've had this particular
discussion a couple times in the past, and have previously concluded that there
is nothing wrong (I'm certain that came up in the context of AI95-0403-1) so I
don't think we should do this same dance again.

Perhaps there is something missing specific to Pure (I didn't try to figure that
out), but I certainly think that Preelaborate is fine. And your generic is not
legal because it is not preelaborable.

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

From: Tucker Taft
Sent: Thursday, May 18, 2017  9:40 PM

Well we seem to agree that as the RM is currently written, the only way to be
sure a generic is pure is for it to be a library unit, with a pragma Pure on it.
I find that completely at odds with my sense of the intent.  At a bare minimum I
would have expected a generic declared inside a declared-pure library package is
required to be pure.  I would also go further to say that for a generic package
to be pure, any generic nested inside it (but not inside a nested subprogram or
task body or declare statement) must also satisfy the requirements for being
pure.

I would agree we should check what compilers do with the case example I
suggested.  I would claim that the outer generic package body should fail when
compiled, because the inner generic package body is not pure.

I ran the following against GNAT and AdaMagic and both complained (even though
there were no instantiations in sight):

  generic
  package Outer is
     pragma Pure(Outer);
     generic
     package Inner is
        procedure Dummy;
     end Inner;
  end Outer;

  package body Outer is
      function Complicated(S : String) return Integer is
      begin
           return Integer'Value(S);
      end Complicated;

      package body Inner is
          Evil_Global : Integer := abs(12345); -- := Complicated("12345");
          procedure Dummy is begin null; end Dummy;
     end Inner;
  end Outer;

Interestingly, AdaMagic is an Ada 95 compiler, and its error message reflected
the old wording of this section:

10.2.1(16) (now replaced, as part of ai95-0036):

    A pure library_item is a preelaborable library_item that does not
    contain the declaration of any variable or named access type, except
    within a subprogram, generic subprogram, task unit, or protected unit.

This makes it clear that in Ada 95, the prohibition of declaring variables
extended into nested generic packages.  There is nothing in ai95-0036 to suggest
that it was intentional to allow nested generic packages to be impure in Ada
2005, so I believe the rewording created this hole that no one ever noticed.
GNAT still enforces the old rule.

So with AdaMagic (relevant to Green Hills and PTC ObjectAda) and GNAT both
rejecting nested impure generics, I don’t believe we have any significant
incompatibilities to worry about.

I reviewed the wording for Preelaborate, and I still believe that it has the
same hole with respect to nested generics.  There is nothing in the current
wording that I could find that requires generic packages that are not library
units to be preelaborable, even when nested within a pre-elaborated package.
All it says is that the declaration and body of a library unit with a pragma
Preelaborate shall be preelaborable, which is defined by what it must *not* do
during its elaboration.  But of course elaborating a generic unit does nothing
at all, so I believe we need to explicitly disallow elaborating a
non-preelaborable generic package.  Hence I believe this wording fix is needed
here as well, and I have verified there is no compatibility issue for GNAT or
AdaMagic with this one either.  I replaced the call on “abs” with the call on
“complicated” and changed the pragma Pure to pragma Preelaborate, and both GNAT
and AdaMagic complained.

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

From: Randy Brukardt
Sent: Thursday, May 18, 2017  10:30 PM

...
> I ran the following against GNAT and AdaMagic and both complained
> (even though there were no instantiations in sight):

Thanks for doing this.

>   generic
>   package Outer is
>      pragma Pure(Outer);
>      generic
>      package Inner is
>         procedure Dummy;
>      end Inner;
>   end Outer;
>
>   package body Outer is
>       function Complicated(S : String) return Integer is
>       begin
>            return Integer'Value(S);
>       end Complicated;
>
>       package body Inner is
>           Evil_Global : Integer := abs(12345); -- := Complicated("12345");
>           procedure Dummy is begin null; end Dummy;
>      end Inner;
>   end Outer;
>
> Interestingly, AdaMagic is an Ada 95 compiler, and its error message
> reflected the old wording of this section:
>
> 10.2.1(16) (now replaced, as part of ai95-0036):
>
>     A pure library_item is a preelaborable library_item that does not
>     contain the declaration of any variable or named access type, except
>     within a subprogram, generic subprogram, task unit, or protected unit.
>
> This makes it clear that in Ada 95, the prohibition of declaring
> variables extended into nested generic packages.
> There is nothing in ai95-0036 to suggest that it was intentional to
> allow nested generic packages to be impure in Ada 2005, so I believe
> the rewording created this hole that no one ever noticed.  GNAT still
> enforces the old rule.

That seems relevant (and it's specific to pure).

> So with AdaMagic (relevant to Green Hills and PTC ObjectAda) and GNAT
> both rejecting nested impure generics, I don't believe we have any
> significant incompatibilities to worry about.

Certainly possible.

> I reviewed the wording for Preelaborate, and I still believe that it
> has the same hole with respect to nested generics.
> There is nothing in the current wording that I could find that
> requires generic packages that are not library units to be
> preelaborable, even when nested within a pre-elaborated package.

Here I disagree. Since a generic body is never elaborated, the only way that
10.2.1(10/2) could mean anything at all is if it applies as an additional
requirement to any generic body within the elaborable construct. Otherwise, we'd
have the nonsense of a non-preelaborable construct that is part of a
preelaborable construct. 10.2.1(10/2) is not conditional! It applies to any
generic body in a preelaborable construct.

(Yes, that probably disallows a non-preelaborable generic body inside of a
subprogram inside of a preelaborable unit. So what? No one outside of ACATS
tests ever writes a generic unit in a subprogram.)

> All it says is that the declaration and body of a library unit with a
> pragma Preelaborate shall be preelaborable, which is defined by what
> it must *not* do during its elaboration.  But of course elaborating a
> generic unit does nothing at all, so I believe we need to explicitly
> disallow elaborating a non-preelaborable generic package.
> Hence I believe this wording fix is needed here as well, and I have
> verified there is no compatibility issue for GNAT or AdaMagic with
> this one either.  I replaced the call on "abs"
> with the call on "complicated" and changed the pragma Pure to pragma
> Preelaborate, and both GNAT and AdaMagic complained.

I don't believe any wording fix is required for preelaborate; we had this
discussion years ago and reached that conclusion then. OTOH, if we're going to
screw up this carefully constructed wording again [;-)] (and clearly we need to
do that for Pure), it wouldn't hurt to clarify that 10.2.1(10/2) applies to any
generic body within an elaborable construct. Even though it is obvious, and even
if it wasn't the Dewar rule clearly applies.

P.S. I really do mean "screw up", too. Everytime we look at this section, people
want to change all kinds of rules in it because it is very hard to understand
but the changes always end up making it worse than it started. (Or end up
wasting a lot of time.) Thus I'm resistant to messing with this clause...

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

From: Tucker Taft
Sent: Friday, May 19, 2017  9:04 AM

I would suggest we continue discussion of this face-to-face in Vienna, as I
believe a “white board” or equivalent could help resolve this one.

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

From: Jeff Cousins
Sent: Tuesday, May 23, 2017  8:52 AM

yes, we'll discuss over a whiteboard, but so far my sympathies are with Randy.

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

From: Randy Brukardt
Sent: Friday, June 9, 2017  1:32 AM

...
> So I think we need to add something to the list of prohibited actions,
> such as:
>
>   (15.5.1) * the elaboration of a generic body that is not pure;
>
> This will ensure that a generic body nested in a generic body must
> pass the rules for being pure, while a generic body nested in a
> subprogram has no such requirement.

In writing this up, it struck me that you pointed out that the Ada 95 wording
was:

    A pure library_item is a preelaborable library_item that does not
    contain the declaration of any variable or named access type, except
    within a subprogram, generic subprogram, task unit, or protected unit.

That asks the question of what about generic package specifications? We didn't
let them have variable declarations in Ada 95, and it doesn't make sense to
allow them now (what is the point of a pure generic that you can never
instantiate as pure??).

AI95-0366-1 seems to imply that not enforcing these rules in generic units was
intended, but AI05-0035-1 makes it clear that they do apply. AI05-0035-1 then
added the generic body rule you are commenting on. But there seems to be no rule
that applies to generic specifications (anywhere). So the text and wording of
AI05-0035-1 is inconsistent.

So now I'm more confused than ever.

Variables should always be banned from pure generic specs, since nothing about
the actuals can turn them into constants. OTOH, the other rules could depend on
the actuals. Yuck.

---

BTW, I've concluded that our difference of opinion over 10.2.1(10/2) boils down
to whether one thinks that 10.2.1(5-9) is applied recursively, or not. My view
is that it is nonsense without such an application, as you don't get to look
willy-nilly inside of anything convenient. And it is talking about "elaborable
constructs", so the only way to enforce it at all on a library unit is to look
inside of other "elaborable constructs" (since object declarations, nested
packages, and the like are "elaborable constructs"). As a compiler implementor,
that's the only possible way to read these rules (you have to write a recursive
function to figure out this rule).

OTOH, since that isn't explicit in the wording, I suppose it is possible to read
these as meaning that there is some sort of magic scope going on here that lets
one look in anything.

So, to head that off, perhaps it would be better to add a final bullet to that
list (after 10.2.1(9/3)):

    * The elaboration of any elaborable construct that is not preelaborable.

which make it crystal-clear that these rules are applied recursively. (Which
would also head off the occasional question from Ada newbys about this.)

Then 10.2.1(10/2) can clearly be read as an additional rule about a specific
elaborable construct (it has to be read that way, as otherwise it would never
apply to anything - 10.2.1(5-9) appear complete otherwise).

A similar fix doesn't work for Pure, sadly, because it talks about compilation
units rather than elaborable constructs. We could fix that by changing it to
talk about program units, but then we still have the issue of variables in
generic specifications.

Sigh. These categorizations are not worth the mess.

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




Questions? Ask the ACAA Technical Agent