Version 1.2 of acs/ac-00173.txt

Unformatted version of acs/ac-00173.txt version 1.2
Other versions for file acs/ac-00173.txt

!standard 10.2.1(5-9)          09-06-01 AC95-00173/01
!class confirmation 09-06-01
!status received no action 09-06-01
!status received 09-02-27
!subject Preelaboration rules need loosening?
!summary
!appendix

!topic Preelaboration rules need loosening?
!reference 10.2.1(5-9)
!from Adam Beneschan 09-02-27
!discussion

I'm looking at a GNAT implementation of Ada.Exceptions, in a-except.ads.  I
think it's from 2007 (I don't know if there's a later version around).  The
interesting parts of this are:


    package Ada.Exceptions is

       pragma Preelaborate_05;

    private

       subtype Code_Loc is System.Address;
       Null_Loc : constant Code_Loc := System.Null_Address;

    end Ada.Exceptions;

Preelaborate_05 is GNAT's own pragma, I realize, but the definition of
Ada.Exceptions indicates that the package must be preelaborable (11.4.1(2)), so
I think we can assume that the package is supposed to be preelaborable.

But it doesn't look like it follows the rules for that.  10.2.1(8) says that one
of the things that makes a construct non-preelaborable is the evaluation of a
_primary_ that is the _name_ of an object, unless the _name_ is a static
expression (or statically denotes a discriminant...).  Here, the elaboration of
the constant declaration causes the evaluation of System.Null_Address, which is
the name of a constant object in System; and it's not a static expression since
it's a deferred constant (since GNAT follows the Implementation Advice that
System.Address is a private type).  (AARM 4.9(24.a)) So I think this declaration
makes Ada.Exceptions non-preelaborable.  (The full view of Null_Occurrence also
includes a component whose elaboration requires evaluating System.Null_Address.)

My point isn't to say "Gotcha" about GNAT doing something illegal, but to whine
that what they're doing seems like a reasonable thing to do in a preelaborable
package, but it appears that the rules don't allow this.  I don't know how this
would be fixable, except to provide a pragma that a programmer could apply to a
deferred constant saying "This will be a static constant, or a preelaborable
constant", or something like that, and then requiring that the full constant be
static or preelaborable if this pragma is used.  Then 10.2.1(8) would allow the
evaluation of names that denote such constants.

(Please note that in the case of System.Null_Address, the full constant
declaration in GNAT's system package is a static expression, since it's 0; but
if System.Address is a two-component record, as in a case I have to deal with,
Null_Address could not be a static constant since it's not a scalar.  So a rule
that depends on something being a "static constant" may not be good enough.)

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

From: Adam Beneschan
Date: Friday, February 27, 2009  1:55 PM

Actually, on further reflection, is there any reason for 10.2.1(8) not to allow
a name that denotes *any* constant?  Any constant object that is named must be
declared in another preelaborable package, and thus its value must satisfy the
rules in 10.2.1(5-9).  So it seems that, at least, if a constant's (full)
declaration is preelaborable, and another object declaration uses that
constant's value as its own initial value, or as a subcomponent of the initial
value, then that shouldn't prevent the second object declaration from
preelaborable also.  (I realize that the constant name could be evaluated in
other contexts besides as an initial value or subcomponent of an initial value
of an object, and maybe those cause problems---I don't know.)

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

From: Randy Brukardt
Date: Friday, May 22, 2009  8:59 PM

...
> Actually, on further reflection, is there any reason for
> 10.2.1(8) not to allow a name that denotes *any* constant?  
> Any constant object that is named must be declared in another 
> preelaborable package, and thus its value must satisfy the rules in 
> 10.2.1(5-9).  So it seems that, at least, if a constant's (full) 
> declaration is preelaborable, and another object declaration uses that 
> constant's value as its own initial value, or as a subcomponent of the 
> initial value, then that shouldn't prevent the second object 
> declaration from preelaborable also.  (I realize that the constant 
> name could be evaluated in other contexts besides as an initial value 
> or subcomponent of an initial value of an object, and maybe those 
> cause problems---I don't know.)

Well, not all constants are really compile-time constant (see AI05-0054-2),
so any of those that aren't really constant would have to be excluded. While
the technique of getting a writable access via Initialize is not allowed -
user-defined Initialize is not preelaboratable initialization (so controlled
parts probably don't need a special exception), the Rosen trick does not
appear to be prevented by preelaboration rules. That is, an immutably limited
type can have preelaborable initialization. But any parts of a constant object
that have immutably limited types would have to exclude the object from being
used in preelaboration (since the values that they could have could not be
known for certain at compile-time).

That of course brings up a privacy issue - the fact that there are (or are
not) components of an immutably limited type is not (in general) known for
a deferred constant. Probably the best fix would be to allow pragma
Preelaboratable_Initialization to be applied to constants as well. But of
course that is a fairly substantial change, so I'm not sure it is worth it.

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

Questions? Ask the ACAA Technical Agent