CVS difference for ai05s/ai05-0190-1.txt
--- ai05s/ai05-0190-1.txt 2011/01/27 06:06:16 1.9
+++ ai05s/ai05-0190-1.txt 2011/02/10 06:52:48 1.10
@@ -1,4 +1,4 @@
-!standard 13.11.3(0) 11-01-23 AI05-0190-1/06
+!standard 13.11.3(0) 11-02-09 AI05-0190-1/07
!class amendment 09-11-03
!status work item 09-11-03
!status received 09-11-03
@@ -94,9 +94,8 @@
Static Semantics
-The pragma applies to all nonderived access types declared in the places defined
-above, including within an instance of a generic unit, unless Storage_Pool or
-Storage_Size is specified for the type:
+The pragma applies to all nonderived access types declared in the places
+defined above, unless Storage_Pool or Storage_Size is specified for the type:
If the default pool is null, the Storage_Size attribute is defined
by the language to be zero.
@@ -105,19 +104,69 @@
If the default pool is a pool, the Storage_Pool attribute is that
pool.
- Otherwise, Redundant[there is no default pool]; the Storage_Pool
- attribute is implementation defined.
+ Redundant[Otherwise, there is no default pool; the Storage_Pool attribute
+ is implementation defined.]
+The language-defined aspect Default_Storage_Pool may be used to define the
+default pool for access types within an instance. The expected type for the
+Default_Storage_Pool aspect is Root_Storage_Pool'Class. The aspect_definition
+must be a name that denotes a variable. This aspect overrides any
+Default_Storage_Pool pragma that might apply to the generic unit.
AARM Ramification: Default_Storage_Pool is the only way to specify the storage
pool for an anonymous access type.
+Note that coextensions should be allocated in the same pool (or on the stack)
+as the outer object (see 13.11); the Storage_Pool of the access discriminant
+(and hence the Default_Storage_Pool) is supposed to be ignored for
+coextensions. This matches the required finalization point for coextensions.
+
+The default storage pool for an allocator that occurs within an instance of a
+generic is defined by the Default_Storage_Pool pragma that applied to the
+generic, or by the Default_Storage_Pool aspect of the instantiation; the
+Default_Storage_Pool pragma that applies to the instantiation is irrelevant.
+
+It is possible to specify the Default_Storage_Pool aspect for an instantiation
+such that allocations will fail. For example, the generic unit might be
+expecting a pool that supports certain sizes and alignments, and the one on the
+instance might be more restrictive. It is the programmer's responsibility to
+get this right.
+
+The semantics of the Default_Storage_Pool aspect are similar to passing a pool
+object as a generic formal, and putting pragma Default_Storage_Pool at the top
+of the generic's visible part, specifying that formal.
+[end AARM Ramification]
+
+
Implementation Permissions
+
+An object created by an allocator that is passed as the actual parameter to an
+access parameter may be allocated on the stack, and automatically reclaimed,
+regardless of the default pool.
+
+AARM Discussion: This matches the required finalization point for such an
+allocated object.
+
+
+NOTE
+Default_Storage_Pool may be used with restrictions No_Coextensions and
+No_Access_Parameter_Allocators (see H.4) to ensure that anonymous allocators
+are not an exception.
+
+
+[End new section 13.11.3]
-An object created by an anonymous allocator may be allocated on the stack, and
-automatically reclaimed, regardless of the default pool.
+Add new restrictions after H.4(8.1/3), i.e. immediately after
+No_Anonymous_Allocators:
+ No_Coextensions
+ There are no coextensions. See 3.10.2.
+
+ No_Access_Parameter_Allocators
+ No allocator that is passed as the actual parameter to an
+ access parameter. See 6.1.
+
!discussion
Expected usage scenarios are:
@@ -138,13 +187,31 @@
!example
+ with My_Pools;
+ package P is
+
+ pragma Default_Storage_Pool(My_Pools.My_Pool);
+
+ type Rec is
+ record
+ Link : access Rec;
+ ...
+ end record;
+
+ type Rec_Ptr is access all Rec;
+ end P;
+
+The Default_Storage_Pool ensures that type Rec_Ptr and the anonymous type of
+Link share the same pool.
+
!ACATS test
ACATS B and C tests are needed.
!ASIS
-This needs an enumeration literal to be added to the type pragma_kinds for the new pragma.
+This needs an enumeration literal to be added to the type pragma_kinds for the
+new pragma.
!appendix
@@ -2614,6 +2681,313 @@
So I don't find this example convincing. The notion of easily applying a debug
pool to an entire program seems more compelling to me (and not that much).
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, January 27, 2011 10:09 PM
+
+I was given a homework task of proposing a revised rule for 7.6.1(11/3).
+
+As a reminder, here is the rule as currently worded (last revised by
+AI05-0051-1):
+
+"The order in which the finalization of a master performs finalization of
+objects is as follows: Objects created by declarations in the master are
+finalized in the reverse order of their creation. For objects that were created
+by allocators for a named access type whose ultimate ancestor is declared in the
+master, this rule is applied as though each such object that still exists had
+been created in an arbitrary order at the first freezing point (see 13.14) of
+the ultimate ancestor type; the finalization of these objects is called the
+finalization of the collection. Objects created by allocators for an anonymous
+access type that are not coextensions of some other object, are finalized in an
+arbitrary order during the finalization of their associated master. After the
+finalization of a master is complete, the objects finalized as part of its
+finalization cease to exist, as do any types and subtypes defined and created
+within the master."
+
+The change applied here was to allow objects allocated from anonymous access
+types to finalize at any time so long as it is done as part of the finalization
+of the correct master.
+
+The problem with this is that AI05-0190-1 allows the specification of a storage
+pool for an anonymous access type (indirectly), so it is possible with the above
+wording for the objects allocated from the storage pool to be finalized *after*
+the storage pool is finalized. For example:
+
+ type Cont is new Ada.Finalization.Controlled with record
+ Is_Groddy : Boolean := True;
+ ...
+ end record;
+ overriding procedure Finalize (Obj : in out Cont) is
+ begin
+ Obj.Is_Groddy := False;
+ end Finalize;
+ function Is_Done (Obj : in Cont) return Boolean is
+ begin
+ return Obj.Is_Groddy;
+ end Is_Done;
+
+ declare
+ My_Pool : Some_Pool_Type; -- (1)
+ pragma Default_Storage_Pool (My_Pool);
+ type Rec is record -- (2)
+ Ptr : access Cont := new Cont;
+ end record;
+ Obj : Rec; -- (3)
+ begin ...
+
+The allocator that is executed as part of the default initialization of Obj will
+allocate from My_Pool. The object (according to the above wording) can be
+finalized at any point during the finalization of this declarative part,
+including before Rec is finalized or after My_Pool is finalized.
+
+It should be clear that this wording is way too broad. This wording would make
+it impossible for there to be any interactions between the finalization of the
+access type and the finalization of other objects in the same master (at least
+in portable code, of course such code might work for a given implementation).
+One such interaction is shown above: the storage pool of the access type.
+
+But that is only the tip of the iceberg. Consider a modification of the above
+example where Rec is a controlled type itself, and Ptr is an allocated component
+that is considered logically part of the record:
+
+ declare
+ My_Pool : Some_Pool_Type; -- (1)
+ pragma Default_Storage_Pool (My_Pool);
+ type Rec is new Ada.Finalization.Controlled record -- (2)
+ Ptr : not null access Cont := new Cont;
+ ...
+ end record;
+ overriding procedure Finalize (Obj : in out Rec) is
+ begin
+ if Is_Done(Obj.Ptr) then
+ ...
+ end if;
+ end Finalize;
+ Obj : Rec; -- (3)
+ begin ...
+
+The proposed wording would allow the allocated object (logically part of
+Rec) to be finalized before the object (but would not require it). This would
+mean that Is_Done would return False instead of True and whatever was supposed
+to happen during the finalization of Obj would not happen.
+
+[Claw has some objects that are structured like this in order to share data
+between 'clones' of objects; the equivalent of Is_Done is used to determine
+whether to do a complete finalization of this object as it is the only existing
+'clone'. If this happened, some objects would never get finalized.]
+
+This example shows that the finalization can happen too early as well as too
+late (I know I said something else during our phone call today, but I hadn't
+thought of this example before then).
+
+The storage pool example shows one way that finalization could be too late, but
+that can happen other ways as well. For instance, consider another example drawn
+from Claw (in Claw, these are at library-level, of course):
+
+ declare
+ My_Lock : Lock_Type;
+ type Root is new Ada.Finalization.Controlled with ...
+ overriding procedure Finalize (Obj : in out Root) is
+ begin
+ My_Lock.Seize;
+ ... -- Do stuff here.
+ My_Lock.Release;
+ end Finalize;
+ Obj : access Root := new Root'(...);
+ begin
+
+Here, the allocator can be finalized at any point, including before Obj or after
+My_Lock. Of course, if it happens after the finalization of My_Lock, the
+finalization will raise Program_Error (because calling a finalized PO raises
+that exception). That's not going to allow a smooth clean-up.
+
+Note that the wording above allows finalization at any time during the
+finalization of the appropriate master. That means for library-level
+declarations like the above, they don't even have to come during the
+finalization of the same package. Obj could be declared in some user package
+that the author of the locking code is not even aware of, and yet finalize after
+the lock has gone away. This seems like madness to me (and it is likely to cause
+madness in the tech-support person that has to figure it out).
+
+Note that the critical point here is that the order needs to be well-defined
+(and not implementation-defined!), and relate fairly closely to the inverse
+order of elaboration. Flexibility seems harmful.
+
+I am supposed to make a suggestion as to how to fix the wording. So far as I can
+tell, the easiest fix is to revert to the previous wording modulo the
+coextension fix (the changes are marked compared to the Ada 2005 7.6.1(11/2)):
+
+"The order in which the finalization of a master performs finalization of
+objects is as follows: Objects created by declarations in the master are
+finalized in the reverse order of their creation. For objects that were created
+by allocators for an access type whose ultimate ancestor is declared in the
+master{ and that are not coextensions of some other object}, this rule is
+applied as though each such object that still exists had been created in an
+arbitrary order at the first freezing point (see 13.14) of the ultimate ancestor
+type; the finalization of these objects is called the finalization of the
+collection. After the finalization of a master is complete, the objects
+finalized as part of its finalization cease to exist, as do any types and
+subtypes defined and created within the master."
+
+The supposed problem with this wording is that it is hard to determine the
+freezing point of an anonymous access type. I'm not actually sure why that's any
+harder than determining the freezing point of a *named* access type; freezing
+points are not good places to do things in general. But we're obviously not
+going to change that.
+
+We could use the point of declaration of the anonymous access type instead
+(unlike a named access type, the storage pool cannot be declared or specified
+after the type declaration, which is why named access types have to use the
+freezing point). I'm unconvinced that really helps anything.
+
+On an mostly unrelated point, I don't think this version (or the Ada 2005
+wording) works right for access parameters, as the declaration or freezing point
+is irrelevant (the master is that of the *call*). So we probably need some
+special wording for that case.
+
+If we adopted all of these suggestions together, we'd end up with something
+like:
+
+"The order in which the finalization of a master performs finalization of
+objects is as follows: Objects created by declarations in the master are
+finalized in the reverse order of their creation. For objects that were created
+by allocators for a named access type whose ultimate ancestor is declared in the
+master, this rule is applied as though each such object that still exists had
+been created in an arbitrary order at the first freezing point (see 13.14) of
+the ultimate ancestor type; the finalization of these objects is called the
+finalization of the collection. Objects created by allocators for an anonymous
+access type that are coextensions of some other object are finalized with that
+other object. Objects created by allocators for an anonymous access parameter
+type are finalized though each such object that still exists had been created in
+an arbitrary order at the evaluation of the containing subprogram call. Objects
+created by other allocators for an anonymous access type are finalized though
+each such object that still exists had been created in an arbitrary order at the
+point of declaration of an anonymous access type. After the finalization of a
+master is complete, the objects finalized as part of its finalization cease to
+exist, as do any types and subtypes defined and created within the master."
+
+There's probably some way to simplify this (the part about the "objects being
+created in an arbitrary order at" some point keeps getting repeated over and
+other). I'm not going to try right now, as I think we need more discussion to
+decide what we want.
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Thursday, January 27, 2011 10:41 PM
+
+Thanks for working on this. You are probably right that we just need to define
+the freezing point for anonymous access types that are not for access discrims
+or access params. Below you are effectively making it at the point of
+declaration, but I suspect we may want to make it later. For anon access
+components, I suspect we want to make it at the point that the immediately
+enclosing type is frozen. For anon access stand-alone objects, I suspect we
+want to make it at the point the stand-alone object is frozen.
+
+****************************************************************
+
+From: Jean-Pierre Rosen
+Sent: Wednesday, February 9, 2011 3:35 AM
+
+> The semantics of the Default_Storage_Pool aspect are similar to
+> passing a pool object as a generic formal, and putting pragma
+> Default_Storage_Pool at the top of the generic's visible part, specifying that
+> formal.
+
+I appreciate the word "similar" to avoid the dreadful "equivalent", but I'm
+wondering about the intended effect in this case:
+
+with Some_Pool;
+procedure Formal_Access is
+
+ Pool_Obj1: Some_Pool.Pool;
+ Pool_Obj2: Some_Pool.Pool;
+ pragma Default_Storage_Pool (Pool_Obj1);
+
+ type Acc is access Integer;
+ Local_Acc : Acc := new Integer;
+
+ generic
+ V : in Acc := new Integer;
+ procedure Gen;
+ procedure Gen is begin null; end Gen;
+
+ procedure Inst1 is new Gen -- (1)
+ with Default_Storage_Pool => Pool_Obj2;
+ procedure Inst2 is new Gen (new Integer) -- (2)
+ with Default_Storage_Pool => Pool_Obj2;
+ procedure Inst2 is new Gen (Local_Acc) -- (3)
+ with Default_Storage_Pool => Pool_Obj2;
+
+begin
+ null;
+end Formal_Access;
+
+Since the visible part of a generic includes the formal part, the "similarity"
+implies that in cases (1) and (2) (default or explicit actual), the object is
+allocated from Pool_Obj2, while obviously (3) is allocated form Pool_Obj1. Is
+this intended?
+
+With my naive user hat on, I would expect (1) to be allocated from
+Pool_Obj2 (it's the generic that is doing the allocation), and (2) to be
+allocated from Pool_Obj1 (I am doing the allocation). Now, don't tell me that
+naive users will have lots of surprises as far as pools and accessibility are
+concerned...
+
+****************************************************************
+
+From: Bob Duff
+Sent: Wednesday, February 9, 2011 7:14 AM
+
+> I appreciate the word "similar" to avoid the dreadful "equivalent",
+> but I'm wondering about the intended effect in this case:
+
+I can get away with "similar" only in the AARM. ;-)
+
+...
+> procedure Inst1 is new Gen -- (1)
+> with Default_Storage_Pool => Pool_Obj2;
+> procedure Inst2 is new Gen (new Integer) -- (2)
+> with Default_Storage_Pool => Pool_Obj2;
+> procedure Inst2 is new Gen (Local_Acc) -- (3)
+> with Default_Storage_Pool => Pool_Obj2;
+
+The default storage pool (whether defined by the pragma or by the aspect) is
+always applying to access types. Not to individual "new"s. The pragma is really
+just a shorthand for putting "for T'Storage_Pool use..." all over the place.
+The aspect is more magical, since it works inside instances, but it still
+applies to types.
+
+So all allocators in the above example use Pool_Obj1.
+There are no access types declared inside Gen, so the aspect clause isn't doing
+anything.
+
+I think it has to be this way, because otherwise type conversions amongst access
+types could cause yet more chaos.
+
+>...Now, don't tell me
+> that naive users will have lots of surprises as far as pools and
+>accessibility are concerned...
+
+Well, it doesn't bother me that using user-defined pools is complicated. I just
+wish the DEFAULT were simple, like it is in every other language I can think of.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Thursday, February 10, 2011 12:40 AM
+
+> I think it has to be this way, because otherwise type conversions
+> amongst access types could cause yet more chaos.
+
+Forget type conversions! If it worked on "new", you would have individual items
+for a single access type allocated from different pools. For a pool-specific
+type, that would be madness (there would be no way to tell what pool to
+deallocate from). For a general access type, it still would be madness, but the
+sort of madness that is somehow expected for general access types. :-) But you
+still couldn't figure out deallocations.
****************************************************************
Questions? Ask the ACAA Technical Agent