CVS difference for ai05s/ai05-0190-1.txt

Differences between 1.9 and version 1.10
Log of other versions for file 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