!standard B.01(17) 07-10-01 AI05-0002-1/04 !standard B.03(62) !standard B.03(71.1/2) !class binding interpretation 04-08-31 !status WG9 Approved 07-11-08 !status ARG Approved 11-0-0 07-06-02 !status work item 05-05-23 !status received 04-08-31 !priority Low !difficulty Medium !subject Unconstrained arrays and C interfacing !summary Access-to-unconstrained-array is not considered L-compatible, so it is not required to be supported. We do not require support for C convention interfacing pragmas for unconstrained array objects, unconstrained array function results, and most unconstrained array parameters. The correspondence between Ada and C for function results is defined. !question The language requires support for C-compatible unconstrained array types (e.g. B.3(42) as applied to Interfaces.C.Char_Array). The correspondence described in B.3(70) applies to both constrained and unconstrained array types. This works fine in the Ada-calling-C direction, but not in the case of Ada-called-by-C. In the latter case, Ada is passed no information about the bounds of the array. How are Ada constructs which require bounds information supposed to work? !wording Replace B.1(17) - T is an access-to-object type, and its designated type is L-compatible, with - T is an access-to-object type, its designated type is L-compatible, and its designated subtype is not an unconstrained array subtype, Add after B.3(62): An implementation need not support an interfacing pragma specifying convention C or C_Pass_By_Copy in the following cases: - an Export or Convention pragma applied to a subprogram which has a parameter of an unconstrained array subtype; - an interfacing pragma applied to a function with an unconstrained array result subtype; - an interfacing pragma applied to an object whose nominal subtype is an unconstrained array subtype. Replace B.3(71.1/2): An Ada parameter of a private type is passed as specified for the full view of the type. with - An Ada parameter of a private type is passed as specified for the full view of the type. - The rules of correspondence given above for parameters of mode IN also apply to the return object of a function. !discussion Consider the following example: with Interfaces.C; package Foo is subtype Char_Array is Interfaces.C.Char_Array; Buffer : Char_Array (1 .. 10) := "1234567890"; Renamed_Slice : Char_Array renames Buffer (3 .. 7); procedure Proc1 (X : Char_Array); pragma Export (C, Proc1, Link_Name => "proc1"); end Foo; package body Foo is procedure Proc1_Callback (X : Char_Array); pragma Import (C, Proc1, Link_Name => "proc1_callback"); -- -- Written in C, this routine takes a char* argument, which it passes -- as the argument of a call to proc1. procedure Assert (Condition : Boolean) is Test_Failed : exception; begin if not Condition then raise Test_Failed; end if; end Assert; procedure Proc1 (X : Char_Array) is use type Char_Array; use type Interfaces.C.Size_T; begin Assert (X'First = Renamed_Slice'First); Assert (X'Last = Renamed_Slice'Last); Assert (X = Renamed_Slice); end Proc1; begin Proc1 (Renamed_Slice); Proc1_Callback (Renamed_Slice); end Foo; The current language rules don't provide any justification for rejecting this example, but it is not clear how it can be implemented. Compare this situation with the treatment of missing discriminants for Unchecked_Union types (AI-216). Discriminant checks are suppressed and each construct which would require accessing a missing discriminant is either statically illegal or is defined to raise Program_Error at runtime. It seems that an analogous set of rules is needed to handle this case. Just as "inferable discriminants" are defined for Unchecked_Union types, a corresponding definition of "inferable bounds" might make sense; on the other hand, this might not be worth the definitional complexity. A call (from Ada) to a convention-C function with an unconstrained array result presents much the same problem; the caller does not know the bounds of the function result. ---- The phrase "for a language" in B.1(12) means that nothing in B.1(12-19) applies in the case where L = Intrinsic. Thus, there is no need to mention the L = Intrinsic case in the revised B.1(17). ---- In the following example (for which support is recommended) procedure Proc (X : String); pragma Import (C, Proc, "Foobar"); it is expected that callers will pass in no bounds information. ---- There has been some concern expressed that under the terms of this proposal, it is not possible to write a portable program that (1) calls a C function that returns a String (a char*, really); or (2) implements a callback that has String (or equivalently Char_Array) parameters. It has never been possible to write portable code which uses these constructs; this proposal is only an explicit recognition of the existing state of affairs. Furthermore, this is not a big problem in practice. In most cases where no better solution is available, it suffices to declare a constrained array subtype (or an access type designating same) that is "big enough". For example, subtype Big_String is Interfaces.C.Char_Array (0 .. 500000); procedure P (X : Big_String); pragma Export (C, P, "aabbcc"); This imprecise representation need only be used until precise bounds information becomes available: procedure P (X : Big_String) is subtype S is Interfaces.C.Char_Array (0 .. Get_Length (X)); type S_Ref is access all S; for S_Ref'Storage_Size use 0; function Cvt is new Unchecked_Conversion (System.Address, S_Ref); -- or use System.Address_To_Access_Conversions instead X_With_Correct_Bounds : S renames Cvt (X'Address).all; -- no subsequent references to X; use X_With_Correct_Bounds instead. It is true that this is somewhat cumbersome, but no better alternative has been proposed. One could explore the alternative of leaving the recommended level of support unmodified and instead working out a definition of the dynamic semantics of these constructs. Following the model of unchecked union types (whose discriminants are not represented at runtime), one could imagine "unchecked array" types (whose bounds are not represented at runtime). The notion of "inferable discriminants" could be generalized to include "inferable bounds" and much of the other wording from AI-216 would also carry over (e.g., discriminant check suppression => index check suppression). Unfortunately, the analogy breaks down in some important ways. All objects of a given unchecked union type are the same size. Thus, discriminant values are not needed in order to compute the size of an unchecked union object. There would be no way to compute the size of one of these "unchecked" array objects. This might be something fundamentally new for some compilers. At the very least, any operation which would normally require a size computation would have to be defined to raise Program_Error instead. This would affect assignment, concatenation, boolean vector operations, inherited constraints, etc. A call to a convention-Ada routine which expects to be passed a dope vector also could not be supported, nor could evaluation of bounds-related array attributes. Finally, the unsupported operations for unchecked union types listed in AI-216 would also be unsupported (i.e., equality testing, membership tests, conversion to a "normal" array type, and streaming attributes). Given that all these commonly used constructs would fail, it would be silly to claim that the language supports these "dopeless" array types. Furthermore, these failures would result in runtime errors whereas the proposed solution, while cumbersome, allows rejection of unsupported constructs at compile time. ---- Tucker Taft reports that "We support unconstrained arrays as parameters in C conventions by giving the array the maximum bounds (i.e. index_subtype'first .. index_subtype'last)". Nothing in this proposal would prevent an implementation from choosing this approach. ---- The distinction between conventions C and C_Pass_By_Copy applies to function results in the same way as to IN mode parameters. Given this example, type C_Rec is record X, Y : Interfaces.C.Int; end record; pragma Convention (C, C_Rec); type C_Pbc_Rec is record X, Y : Interfaces.C.Int; end record; pragma Convention (C_Pass_By_Copy, C_Pbc_Rec); function C_Func return C_Rec; pragma Import (C, C_Func); function C_Pbc_Func return C_Pbc_Rec; pragma Import (C, C_Pbc_Func); and given that that type t is a C struct corresponding to the two Ada types, function C_Func corresponds to a t*-valued C function whereas function C_Pbc_Func corresponds to a t-valued C function. !corrigendum B.1(17) @drepl @xbullet-compatible,> @dby @xbullet-compatible, and its designated subtype is not an unconstrained array subtype,> !corrigendum B.3(62) @dinsa An implementation may provide additional declarations in the C interface packages. @dinss An implementation need not support an interfacing pragma specifying convention C or C_Pass_By_Copy in the following cases: @xbullet @xbullet @xbullet !corrigendum B.3(71.1/2) @drepl An Ada parameter of a private type is passed as specified for the full view of the type. @dby @xbullet @xbullet also apply to the return object of a function.> !example (See discussion.) !ACATS test Create a C-Test checking the correspondences for function returns. The rest of the changes are a permission to not support, and thus are not testable. !appendix From: Randy Brukardt Sent: Tuesday, August 31, 2004 6:02 PM Steve wrote: > The language requires support for C-compatible unconstrained array types > (e.g. B.3(42) as applied to Interfaces.C.Char_Array). The correspondence > described in B.3(70) applies to both constrained and unconstrained array types. > This works fine in the Ada-calling-C direction, but not in the case of > Ada-called-by-C. In the latter case, Ada is passed no information about the > bounds of the array. How are Ada constructs which require bounds information > supposed to work? Obviously, they don't. Since this is just Implementation Advice anyway, it can be ignored if it says something that is nonsense. Certainly, that is true in this case. We can also apply Dewar's rule here - the language says something stupid (C certainly can't call unconstrained arrays). Janus/Ada just rejects any pragma Import or Export that it doesn't know how to code generate. While I followed the IA as much as possible, I didn't sweat anything that I couldn't figure out... Still, the IA should be fixed (thus I opened an AI as noted above). ... >Compare this situation with the treatment of missing discriminants for >Unchecked_Union types (AI-216). Discriminant checks are suppressed and each >construct which would require accessing a missing discriminant is either >statically illegal or is defined to raise Program_Error at runtime. >It seems that an analogous set of rules is needed to handle this case. >Just as "inferable discriminants" are defined for Unchecked_Union types, >a corresponding definition of "inferable bounds" might make sense; on the other >hand, this might not be worth the definitional complexity. Certainly not. We should just not allow such declarations; they cannot mean anything useful. >A call (from Ada) to a convention-C function with an unconstrained array result >presents much the same problem; the caller does not know the bounds of the >function result. Right; this is the same problem. It should be noted that a legality rule would be OK here, because the rule would not need to depend on the representation of the unconstrained array: *all* unconstrained arrays should be banned in parameters of Export to C (and most other languages, too) and function returns of Import from C. But this rule probably should be IA as well, because we don't want to prevent an implementation from doing this if they can figure out some meaning for it. **************************************************************** From: Tucker Taft Sent: Tuesday, August 31, 2004 8:21 PM We support unconstrained arrays as parameters in C conventions by giving the array the maximum bounds (i.e. index_subtype'first .. index_subtype'last). Clearly there needs to be some other parameter which conveys the length, or some convention such as null termination. We have one customer who has requested a new convention, which we call "C_With_Array_Len" which adds an extra parameter in the C interface corresponding to the length of the array, so that the bounds become index_subtype'first .. index_subtype'first + len-param - 1. If the array is multidimensional, a separate "len" parameter is added for each dimension. I'm not recommending this to be standardized, but it does indicate that some people are uncomfortable with our "standard" max-range approach. **************************************************************** From: Robert Dewar Sent: Wednesday, September 1, 2004 8:39 AM Related to this is the issue that Address_To_Access conversions cannot work with unconstrained arrays. **************************************************************** From: Randy Brukardt Sent: Wednesday, September 1, 2004 3:46 PM For the record, that's not strictly true; it works fine in Janus/Ada. But that's because we ignore Implementation Advice 13.3(14) [following it would have been incompatible with our Ada 83 compilers, and would have caused problems with some run-time code - as then there would be no way to access the array descriptors. It also would mean that it would be impossible to use an Address Clause with a constrained at creation array object.]. ('Address and 'Access in Janus/Ada always point at the top-level object; for an array of size not known at compile-time, that's the array descriptor, not the data. The same is true for a component constrained by a discriminant.) But it's clearly not portable (and contrary to the mentioned IA), so it would make sense to discuss this case as well in the AI. **************************************************************** From: Robert Dewar Sent: Wednesday, September 1, 2004 4:17 PM > For the record, that's not strictly true; it works fine in Janus/Ada. But > that's because we ignore Implementation Advice 13.3(14) Ouch! I would guess most of our customers big programs depend on that IA :-) > But it's clearly not portable (and contrary to the mentioned IA), so it > would make sense to discuss this case as well in the AI. Well if making something work means breaking some (really important in my view) IA, that's definitely an issue :-) What we do is to generate a warning that To_Pointer cannot be expected to be useful in this case: 3. package A is new System.Address_To_Access_Conversions (String); | >>> warning: in instantiation at s-atacco.ads:45 >>> warning: Object is unconstrained array type >>> warning: To_Pointer results may not have bounds In fact in GNAT the "may" is here because if the address was originally obtained by taking the address of a string, then the bounds may actually be where they are expected to be :-) **************************************************************** From: Robert Dewar Sent: Wednesday, September 1, 2004 4:24 PM > We have one customer who has requested a new convention, which > we call "C_With_Array_Len" which adds an extra parameter in > the C interface corresponding to the length of the array, > so that the bounds become index_subtype'first .. index_subtype'first + > len-param - 1. If the array is multidimensional, a separate > "len" parameter is added for each dimension. > > I'm not recommending this to be standardized, but it does indicate > that some people are uncomfortable with our "standard" max-range > approach. Actually I think this is something that would be worth while semi-standardizing. GNAT tends to absorb such things anyway, so I think it might be worth including this as implementation advice. I trust it won't get too complicated (*). An alternative to having an extra parameter is to pass a descriptor. This is what is done in VMS for pass by descriptor. It also seems a shame to assume index_subtype'first, why not pass the bounds properly? (*) We just finished implementing the full blown Unchecked_Union. What a nightmare! And the sad thing is that our best guess is that none of the fancy extra features will get actually used :-( **************************************************************** From: Tucker Taft Sent: Wednesday, September 1, 2004 4:48 PM > It also seems a shame to assume index_subtype'first, why not pass > the bounds properly? We are trying to present an interface that means something to a C programmer. Arrays in C only have a length. The low bound is always 0. In Ada, the programmer gets to choose what is the more natural low bound (0, 1, whatever), but the C programmer needn't be bothered with this nicety. > (*) We just finished implementing the full blown Unchecked_Union. > What a nightmare! And the sad thing is that our best guess is > that none of the fancy extra features will get actually used :-( In our C code, we have many struct/union trees that match what the "full blown" Unchecked_Union is designed to support. For what that is worth... **************************************************************** From: Robert Dewar Sent: Wednesday, September 1, 2004 5:14 PM Tucker Taft wrote: > In our C code, we have many struct/union trees that match what > the "full blown" Unchecked_Union is designed to support. > For what that is worth... But C unions don't allow more than one component in each variant! Also, it is not the data layout that is the issue, it is all the special casees of allowing things like equality when you can figure out the discriminants. Did you implement this feature fully yet? **************************************************************** From: Pascal Leroy Sent: Thursday, September 2, 2004 7:38 AM If we are in the business of fixing A_To_A_Conversion, I would be in favor of making the access type a formal type (I know, for compatibility a new generic would be required). It is totally dumb that each instantiation of this generic creates a collection, for which you cannot specify the storage size. **************************************************************** From: Robert A. Duff Sent: Thursday, September 2, 2004 7:56 AM Mea Culpa. I wrote that section. I did it that way on purpose, but after having used the thing a few times, I realized it is, as you say, "totally dumb". But I don't think it's important enough to bother fixing. **************************************************************** From: Robert Dewar Sent: Friday, September 3, 2004 3:14 AM Indeed! This is a fundamental inconsistency which should be fixed. moreover you cannot specify a storage pool, which is even worse. **************************************************************** From: Tucker Taft Sent: Friday, September 3, 2004 7:19 AM I'm not sure I understand the concern here. The generic is intended to provide an access value given an address. It was never expected that such an access value would be considered equivalent to an access value created by an allocator. This generic is more like GNAT's 'Unrestricted_Access. So what possible meaning would there be for the storage size or storage pool, since those attributes are relevant only for allocators (and unchecked deallocation)? **************************************************************** From: Tucker Taft Sent: Friday, September 3, 2004 8:20 AM I might add that anonymous access types, which we are now allowing in more contexts, have the same property of not allowing the specification of storage size or storage pool. So this all sounds like a tempest in a teapot to me. Do people really have a bunch of these A_To_A instantiations all over the place? **************************************************************** From: Robert A. Duff Sent: Friday, September 3, 2004 8:58 AM I agree that it's a tempest in a tea pot. I think the issue is not Storage_Pool per se. The issue is that if you have an access type, and you want to convert an Address value to that type, you have to call the To_Pointer function from the instance, and then convert *that* to your access type, using a normal type conversion. It would be slightly cleaner to be able to convert directly. So why don't you just use the access type declared in the instance of Address_To_Access_Conversions? I think Pascal was saying, "Because I want a Storage_Size clause", and Robert was saying, "Yeah, and because I want a Storage_Pool clause." Another obvious reason is that your access type belongs in a package spec, and the instance belongs in the body. I still say: it's not broken enough to fix. Just put in the silly extra type conversion. One hopes not to use this feature very often! By the way, why would you want to use Address_To_Access_Conversions to go the other direction? I mean, isn't X.all'Address sufficient? (I usually don't want nulls in these cases...) P.S. The reason I didn't do it Pascal's way in the first place, is that I imagined the only usage would be for "peek/poke" functionality. That is, I thought you would always do something like this: Thing: Integer renames To_Pointer(Some_Address).all; Thing := Thing + 1; with an immediate .all, and you don't care what the access type is. Declaring one and passing it to the instantiation is just annoying verbosity in this case. (In fact, you want an anonymous access type!) **************************************************************** From: Robert Dewar Sent: Friday, September 3, 2004 3:54 PM Well I think it would be reasonable to have a note in the RM noting the case that is unlikely to work, or rather unlikely to work in anything approximating a portable manner. > I think the issue is not Storage_Pool per se. The issue is that if you > have an access type, and you want to convert an Address value to that > type, you have to call the To_Pointer function from the instance, and > then convert *that* to your access type, using a normal type conversion. > It would be slightly cleaner to be able to convert directly. Can you say what you mean here, you can't just go converting access types when storage pools are involved??? **************************************************************** From: Randy Brukardt Sent: Friday, September 3, 2004 7:12 PM While I generally agree with you and Pascal on this topic, I don't understand the above. There is no restriction on converting between general access types as long as they designate the same type. The only problem comes if you call Unchecked_Deallocation on an access from another pool; that's defined to be erroneous in 13.11.2(16). Even if you had an A_to_A that allowed an access type with a pool, I would hope that using Unchecked_Deallocation on the result would still be erroneous. (It certainly wouldn't be meaningful unless it was previous allocated from that pool - in which case, why the heck do you need A_to_A??) So there isn't going to be any semantic difference here. The real issue to me is that we expanded the use of anonymous access types specifically so we could get rid of unnecessary explicit conversions, as they're confusing to the reader (a type conversion is supposed to indicate something happening). This is another source of unnecessary conversions, and it would make sense to get rid of them here as well. **************************************************************** From: Robert A. Duff Sent: Friday, September 3, 2004 7:30 PM > Well I think it would be reasonable to have a note in the RM noting > the case that is unlikely to work, or rather unlikely to work in > anything approximating a portable manner. You mean the access-to-unc-array case? Yeah, a note seems reasonable. > > I think the issue is not Storage_Pool per se. The issue is that if you > > have an access type, and you want to convert an Address value to that > > type, you have to call the To_Pointer function from the instance, and > > then convert *that* to your access type, using a normal type conversion. > > It would be slightly cleaner to be able to convert directly. > > Can you say what you mean here, you can't just go converting access > types when storage pools are involved??? The package as currently defined: generic type Object(<>) is limited private; package System.Address_To_Access_Conversions is pragma Preelaborate(Address_To_Access_Conversions); type Object_Pointer is access all Object; function To_Pointer(Value : Address) return Object_Pointer; ... end System.Address_To_Access_Conversions; I thought Pascal's proposal was to change it to: generic type Object(<>) is limited private; type Object_Pointer is access all Object; package System.Address_To_Access_Conversions is pragma Preelaborate(Address_To_Access_Conversions); function To_Pointer(Value : Address) return Object_Pointer; ... end System.Address_To_Access_Conversions; That is, make the pointer type into a generic formal. With the current language, one can do this: package Things is type Thing is ... type Thing_Ptr is access all Thing; for Thing_Ptr'Storage_Pool use ...; ... end Things; with System.Address_To_Access_Conversions; package body Things is package Conv is new System.Address_To_Access_Conversions(Thing); function F(...) return Thing_Ptr is begin return Thing_Ptr(Conv.To_Pointer(Some_Address)); With Pascal's proposal, the body becomes: with System.Address_To_Access_Conversions; package body Things is package Conv is new System.Address_To_Access_Conversions(Thing, Thing_Ptr); function F(...) return Thing_Ptr is begin return Conv.To_Pointer(Some_Address); That is, the type conversion to Thing_Ptr is eliminated. Either way, Thing_Ptr can have a Storage_Pool or Storage_Size clause. And either way, the programmer had better ensure that Some_Address "makes sense" as a value of type Thing_Ptr. And either way, if you try to use Unchecked_Dealloc, you better make sure it originally came from the same pool. **************************************************************** From: Robert A. Duff Sent: Friday, September 3, 2004 7:41 PM > While I generally agree with you and Pascal on this topic, I don't > understand the above. There is no restriction on converting between general > access types as long as they designate the same type. The only problem comes > if you call Unchecked_Deallocation on an access from another pool; that's > defined to be erroneous in 13.11.2(16). Right. > Even if you had an A_to_A that allowed an access type with a pool, I would > hope that using Unchecked_Deallocation on the result would still be > erroneous. Yes. >... (It certainly wouldn't be meaningful unless it was previous > allocated from that pool - in which case, why the heck do you need A_to_A??) If you're playing games with storage pools, you might have a function that allocates some storage, and returns a pointer to that storage plus some offset. And deallocate might need to recover the original storage pointer by subtracting that offset. I've done something like that in low-level storage-pool code, where *this* storage pool is allocating hunks of storage from an underlying storage pool. > So there isn't going to be any semantic difference here. Right. > The real issue to me is that we expanded the use of anonymous access types > specifically so we could get rid of unnecessary explicit conversions, as > they're confusing to the reader (a type conversion is supposed to indicate > something happening). This is another source of unnecessary conversions, and > it would make sense to get rid of them here as well. Right. So should it be: generic type Object(<>) is limited private; package System.Address_To_Access_Conversions is pragma Preelaborate(Address_To_Access_Conversions); function To_Pointer(Value : Address) return access all Object; ... ^^^^^^^^^^^^^^^^^ end System.Address_To_Access_Conversions; where the result of To_Pointer can be *implicitly* converted to whatever appropriate access type you like? Or something like that? **************************************************************** From: Pascal Leroy Sent: Monday, September 6, 2004 4:00 AM Well, it's nice to reduce the number of implicit conversions, but it doesn't solve the problem I had in mind. Say that I am getting an address from some low-level mechanism, e.g. calling a C library. I want to convert this address into an Ada access-to-record, to access individual fields in a type-safe manner. There are various useful properties that I am unable to express in Ada because the silly A_To_A_Conversion insists on declaring the access type itself: 1 - I am not going to change the allocated structure; I'd like to have an access-to-constant. 2 - I am not going to do any allocation on the Ada side; I'd like to have storage size of 0. 3 - I may be doing allocations/deallocations on the Ada side, but they better go through the storage management mechanism provided by the C library, lest plague and pestilence ensue; I'd like to specify a storage pool. All three would be possible to express if the generic took an access type as a parameter (OK, we would need two generics for access-to-constant and access-to-variable). And please don't tell me that I can just convert the access type exported by the instantiation to a user-declared one with the right properties, because that doesn't give me any additional safety: I cannot prevent code from writing/allocating/deallocating through the type exported by the instantiation. **************************************************************** From: Robert A. Duff Sent: Monday, September 6, 2004 8:48 AM > All three would be possible to express if the generic took an access type > as a parameter (OK, we would need two generics for access-to-constant and > access-to-variable). The above are all true. I just don't think it's important enough to fix. >...And please don't tell me that I can just convert the > access type exported by the instantiation to a user-declared one with the > right properties,... Too late. ;-) I already told you that. >...because that doesn't give me any additional safety: I > cannot prevent code from writing/allocating/deallocating through the type > exported by the instantiation. Well, you can work around that by instantiating in a fairly invisible place. E.g. function To_Ptr(X: System.Address) return Some_Ptr is package Instance is new A_To_A_Conversions(...); begin return Some_Ptr(Instance.To_Pointer(X)); end To_Ptr; Or leave out Some_Ptr() if the conversion is implicit. These annoyances would bother me more if A_To_A_C were something I use every day. I must admit that I've used Unchecked_Conversion instead, sometimes. **************************************************************** From: Robert I. Eachus Sent: Monday, September 6, 2004 11:46 AM "Fixing" this issue would in my mind be a bad idea. It would add an unnecessary upward incompatibility to the language. But adding separate children of System that takes access parameters may be worth doing. The question for implementors is whether or not adding the the following package to the standard would require much if any work: generic type Object(<>) is limited private; type Object_Pointer is access all Object; package System.Address_To_Named_Access_Conversions is pragma Preelaborate(Address_To_Named_Access_Conversions); function To_Pointer(Value : Address) return access all Object; function To_Address(Value : Object_Pointer) return Address; pragma Convention(Intrinsic, To_Pointer); pragma Convention(Intrinsic, To_Address); end System.Address_To_Named_Access_Conversions; generic type Object(<>) is limited private; type Object_Pointer is access constant Object; package System.Address_To_Constant_Access_Conversions is pragma Preelaborate(Address_To_Constant_Access_Conversions); function To_Pointer(Value : Address) return access constant Object; function To_Address(Value : Object_Pointer) return Address; pragma Convention(Intrinsic, To_Pointer); pragma Convention(Intrinsic, To_Address); end System.Address_To_Constant_Access_Conversions; My guess is that the work required would be mostly cut and paste (as would the work in the RM), so it may be easier to add these packages than to continue the debate. **************************************************************** From: Robert A. Duff Sent: Monday, September 6, 2004 12:33 PM By "fixing", I meant "adding separate children...", which is exactly what Pascal suggested. But note that Pascal or any other programmer can implement the desired functionality in plain portable Ada 95: generic type Object(<>) is limited private; type Object_Pointer is access all Object; package System.Address_To_Named_Access_Conversions is pragma Preelaborate(Address_To_Named_Access_Conversions); function To_Pointer(Value : Address) return Object_Pointer; function To_Address(Value : Object_Pointer) return Address; pragma Inline(To_Pointer); pragma Inline(To_Address); end System.Address_To_Named_Access_Conversions; with Address_To_Access_Conversions; package System.Address_To_Named_Access_Conversions is package A_To_A is new Address_To_Access_Conversions(Object); function To_Pointer(Value : Address) return return Object_Pointer is begin return Object_Pointer(A_To_A.To_Pointer(Value)); end To_Pointer; function To_Address(Value : Object_Pointer) return Address is begin return Value.all'Address; OR (if you want to allow nulls): return To_Address(A_To_A.Object_Pointer(Value)); end To_Address; end System.Address_To_Named_Access_Conversions; and similarly for the access-constant version. **************************************************************** From: Robert Dewar Sent: Monday, September 6, 2004 12:50 PM This is not portable Ada, you can't go adding children to System yourself! **************************************************************** From: Robert A. Duff Sent: Monday, September 6, 2004 2:08 PM Got me! I forgot to delete "System." from the example. I did remember to change pragma Intrinsic to pragma Inline. ;-) ****************************************************************