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