* How to get around "access type must not be outside generic unit" @ 2006-12-17 10:07 Michael Erdmann 2006-12-17 12:45 ` Pascal Obry 2007-01-23 18:18 ` [Revisited] How to get around "access type must not be outside generic unit" (was: How to get around "access type must not be outside generic unit") Dmitry A. Kazakov 0 siblings, 2 replies; 19+ messages in thread From: Michael Erdmann @ 2006-12-17 10:07 UTC (permalink / raw) Dear all, after installing the latest version of GNAT on my linux box i encounter a problem with old source code. The Fragment below shows the problem: ---- usage.ads generic type Data_Type is private; package Usage is function Install return Boolean ; procedure Doit( X : in out Data_Type ); end Usage; ---- usage.adb with Base; use Base; package body Usage is function Install return Boolean is begin return True; end Install; procedure Doit( X : in out Data_Type ) is begin null; end Doit; begin Register("Doit", Install'Access); <<<< offending line end Usage; gnade@hal:~/test> gnatmake -c usage.adb gcc -c usage.adb usage.adb:16:28: access type must not be outside generic unit gnatmake: "usage.adb" compilation error What is the reason for this new compiler check and what can i do about it? Regards M.Erdmann ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-17 10:07 How to get around "access type must not be outside generic unit" Michael Erdmann @ 2006-12-17 12:45 ` Pascal Obry 2006-12-17 14:28 ` Michael Erdmann 2006-12-18 3:35 ` Brian May 2007-01-23 18:18 ` [Revisited] How to get around "access type must not be outside generic unit" (was: How to get around "access type must not be outside generic unit") Dmitry A. Kazakov 1 sibling, 2 replies; 19+ messages in thread From: Pascal Obry @ 2006-12-17 12:45 UTC (permalink / raw) To: Michael Erdmann Michael Erdmann a �crit : > gnade@hal:~/test> gnatmake -c usage.adb > gcc -c usage.adb > usage.adb:16:28: access type must not be outside generic unit > gnatmake: "usage.adb" compilation error > > What is the reason for this new compiler check and what can i do > about it? Solution 1) Declare register using an anonymous access type : procedure Register (Str : in String; A : access function return Boolean); Solution 2) Move access to generic spec with Base; use Base; generic type Data_Type is private; package Usage is function Install return Boolean ; procedure Doit( X : in out Data_Type ); Install_Access : P_Access := Install'Access; end Usage; ---- usage.adb with Base; use Base; package body Usage is function Install return Boolean is begin return True; end Install; procedure Doit( X : in out Data_Type ) is begin null; end Doit; begin Register ("Doit", Install_Access); end Usage; package Base is type P_Access is access function return Boolean; procedure Register (Str : in String; A : P_Access); end Base; Pascal. -- --|------------------------------------------------------ --| Pascal Obry Team-Ada Member --| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE --|------------------------------------------------------ --| http://www.obry.net --| "The best way to travel is by means of imagination" --| --| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595 ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-17 12:45 ` Pascal Obry @ 2006-12-17 14:28 ` Michael Erdmann 2006-12-17 15:53 ` Pascal Obry 2006-12-17 20:49 ` Robert A Duff 2006-12-18 3:35 ` Brian May 1 sibling, 2 replies; 19+ messages in thread From: Michael Erdmann @ 2006-12-17 14:28 UTC (permalink / raw) Thanks; Solution 2 works, see below :-) Pascal Obry wrote: > Michael Erdmann a �crit : >> gnade@hal:~/test> gnatmake -c usage.adb >> gcc -c usage.adb >> usage.adb:16:28: access type must not be outside generic unit >> gnatmake: "usage.adb" compilation error >> >> What is the reason for this new compiler check and what can i do >> about it? > > Solution 1) Declare register using an anonymous access type : > > procedure Register > (Str : in String; A : access function return Boolean); > Actually this does not work; compiler complains the anonymous types are not allowed here. > Solution 2) Move access to generic spec > > with Base; use Base; > > generic > type Data_Type is private; > package Usage is > > function Install return Boolean ; > procedure Doit( X : in out Data_Type ); > > Install_Access : P_Access := Install'Access; > > end Usage; > This works. In order to make Install_Access invisible to the rest of the world i make it private. with Base; use Base; generic type Data_Type is private; package Usage is function Install return Boolean ; procedure Doit( X : in out Data_Type ); private Install_Access : constant Callback_Access := Install'Access; end Usage; But what is the gain of doing it like this. I don't see any gain in security..?! > ---- usage.adb > with Base; use Base; > > package body Usage is > > function Install return Boolean is > begin > return True; > end Install; > > procedure Doit( X : in out Data_Type ) is > begin > null; > end Doit; > > begin > Register ("Doit", Install_Access); > end Usage; > > package Base is > > type P_Access is access function return Boolean; > > procedure Register (Str : in String; A : P_Access); > > end Base; > > Pascal. > ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-17 14:28 ` Michael Erdmann @ 2006-12-17 15:53 ` Pascal Obry 2006-12-17 20:49 ` Robert A Duff 1 sibling, 0 replies; 19+ messages in thread From: Pascal Obry @ 2006-12-17 15:53 UTC (permalink / raw) To: Michael Erdmann Michael Erdmann a �crit : > Thanks; Solution 2 works, see below :-) > > Pascal Obry wrote: >> Michael Erdmann a �crit : >>> gnade@hal:~/test> gnatmake -c usage.adb >>> gcc -c usage.adb >>> usage.adb:16:28: access type must not be outside generic unit >>> gnatmake: "usage.adb" compilation error >>> >>> What is the reason for this new compiler check and what can i do >>> about it? >> Solution 1) Declare register using an anonymous access type : >> >> procedure Register >> (Str : in String; A : access function return Boolean); >> > Actually this does not work; compiler complains the anonymous types > are not allowed here. It works as I have tested it. You probably missed the -gnat05 compiler option or you are using a compiler older than mine. Pascal. -- --|------------------------------------------------------ --| Pascal Obry Team-Ada Member --| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE --|------------------------------------------------------ --| http://www.obry.net --| "The best way to travel is by means of imagination" --| --| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595 ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-17 14:28 ` Michael Erdmann 2006-12-17 15:53 ` Pascal Obry @ 2006-12-17 20:49 ` Robert A Duff 1 sibling, 0 replies; 19+ messages in thread From: Robert A Duff @ 2006-12-17 20:49 UTC (permalink / raw) Michael Erdmann <michael.erdmann@snafu.de> writes: >> procedure Register >> (Str : in String; A : access function return Boolean); >> > Actually this does not work; compiler complains the anonymous types > are not allowed here. It's an Ada 2005 feature. > private > Install_Access : constant Callback_Access := Install'Access; > But what is the gain of doing it like this. I don't see any > gain in security..?! It prevents dangling pointers. See AI-229. - Bob ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-17 12:45 ` Pascal Obry 2006-12-17 14:28 ` Michael Erdmann @ 2006-12-18 3:35 ` Brian May 2006-12-18 7:49 ` Jean-Pierre Rosen 2006-12-18 20:32 ` Michael Erdmann 1 sibling, 2 replies; 19+ messages in thread From: Brian May @ 2006-12-18 3:35 UTC (permalink / raw) >>>>> "Pascal" == Pascal Obry <pascal@obry.net> writes: Pascal> Solution 2) Move access to generic spec ... Pascal> begin Register ("Doit", Install_Access); end Usage; How is this any different from using Install'Access? I would have thought since Install was defined within the generic unit, Install'Access would be OK. Or does Install'Access imply a temporary local variable? Put another way, how can you create a dangling pointer with Install'Access but not Install_Access? Maybe I am just not awake today, -- Brian May <bam@snoopy.apana.org.au> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-18 3:35 ` Brian May @ 2006-12-18 7:49 ` Jean-Pierre Rosen 2006-12-18 23:15 ` Brian May 2006-12-18 20:32 ` Michael Erdmann 1 sibling, 1 reply; 19+ messages in thread From: Jean-Pierre Rosen @ 2006-12-18 7:49 UTC (permalink / raw) Brian May a �crit : >>>>>> "Pascal" == Pascal Obry <pascal@obry.net> writes: > > Pascal> Solution 2) Move access to generic spec > > ... > > Pascal> begin Register ("Doit", Install_Access); end Usage; > > How is this any different from using Install'Access? > > I would have thought since Install was defined within the generic > unit, Install'Access would be OK. > > Or does Install'Access imply a temporary local variable? It's all about the contract model. When you instantiate a generic, you are supposed to "see" the specification, but not the body. Hence, declarations in the specification "assume the best", i.e. anything is allowed, assuming that if certain constructs are illegal due to the properties of the actual parameters, the instantiation will be rejected. Since you are not supposed to see the body, this is not possible for declarations in the body, hence the body "assumes the worst": anything that could be illegal *is* illegal. Therefore, moving the offending declaration from body to spec can solve the problem. > Put another way, how can you create a dangling pointer with > Install'Access but not Install_Access? > Just instantiate that generic inside a procedure. Install becomes a local function of that procedure, but you would keep a 'access on it in a global structure. Taking the 'access in the specification is illegal, and (as explained above), the instantiation would be illegal. -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-18 7:49 ` Jean-Pierre Rosen @ 2006-12-18 23:15 ` Brian May 2006-12-19 1:48 ` Randy Brukardt 2006-12-19 7:41 ` Jean-Pierre Rosen 0 siblings, 2 replies; 19+ messages in thread From: Brian May @ 2006-12-18 23:15 UTC (permalink / raw) >>>>> "Jean-Pierre" == Jean-Pierre Rosen <rosen@adalog.fr> writes: Jean-Pierre> Just instantiate that generic inside a procedure. Jean-Pierre> Install becomes a local function of that procedure, Jean-Pierre> but you would keep a 'access on it in a global Jean-Pierre> structure. OK, I understand up to here. Jean-Pierre> Taking the 'access in the specification is illegal, Jean-Pierre> and (as explained above), the instantiation would be Jean-Pierre> illegal. I get lost here. Why is taking the 'access value in the specification illegal if the generic has been instantiated inside a procedure? -- Brian May <bam@snoopy.apana.org.au> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-18 23:15 ` Brian May @ 2006-12-19 1:48 ` Randy Brukardt 2006-12-19 7:41 ` Jean-Pierre Rosen 1 sibling, 0 replies; 19+ messages in thread From: Randy Brukardt @ 2006-12-19 1:48 UTC (permalink / raw) "Brian May" <bam@snoopy.apana.org.au> wrote in message news:sa47iwo94o8.fsf@margay.local... > >>>>> "Jean-Pierre" == Jean-Pierre Rosen <rosen@adalog.fr> writes: ... > Jean-Pierre> Taking the 'access in the specification is illegal, > Jean-Pierre> and (as explained above), the instantiation would be > Jean-Pierre> illegal. > > I get lost here. Why is taking the 'access value in the specification > illegal if the generic has been instantiated inside a procedure? The accessibility check fails. That's the check that prevents dangling pointers. JP is assuming that the Register routine and it's access type is declared at the library level when he "says inside of a procedure". Note that the rule is "assume-the-worst", and it is always possible to instantiate at a more nested level than the Register routine is defined. So the 'access is always illegal in a body. OTOH, in specifications the rule is "assume-the-best and recheck on instantiation". So if you put the 'access in the private part, it is OK (until you write a nested instance, but then that instance is illegal). Randy. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-18 23:15 ` Brian May 2006-12-19 1:48 ` Randy Brukardt @ 2006-12-19 7:41 ` Jean-Pierre Rosen 1 sibling, 0 replies; 19+ messages in thread From: Jean-Pierre Rosen @ 2006-12-19 7:41 UTC (permalink / raw) Brian May a �crit : > Jean-Pierre> Taking the 'access in the specification is illegal, > Jean-Pierre> and (as explained above), the instantiation would be > Jean-Pierre> illegal. > > I get lost here. Why is taking the 'access value in the specification > illegal if the generic has been instantiated inside a procedure? It is a 'access on a procedure declared inside the package. Therefore, the lifetime of the designated procedure is the scope of the enclosing procedure, and you can't assign it to an access object whose lifetime is longer. -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-18 3:35 ` Brian May 2006-12-18 7:49 ` Jean-Pierre Rosen @ 2006-12-18 20:32 ` Michael Erdmann 2006-12-18 20:57 ` Randy Brukardt 1 sibling, 1 reply; 19+ messages in thread From: Michael Erdmann @ 2006-12-18 20:32 UTC (permalink / raw) Brian May wrote: >>>>>> "Pascal" == Pascal Obry <pascal@obry.net> writes: > > Pascal> Solution 2) Move access to generic spec > > ... > > Pascal> begin Register ("Doit", Install_Access); end Usage; > > How is this any different from using Install'Access? > > I would have thought since Install was defined within the generic > unit, Install'Access would be OK. > > Or does Install'Access imply a temporary local variable? > > Put another way, how can you create a dangling pointer with > Install'Access but not Install_Access? This is exactly what came into my mind when i was looking at the offending code. > > Maybe I am just not awake today, ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: How to get around "access type must not be outside generic unit" 2006-12-18 20:32 ` Michael Erdmann @ 2006-12-18 20:57 ` Randy Brukardt 0 siblings, 0 replies; 19+ messages in thread From: Randy Brukardt @ 2006-12-18 20:57 UTC (permalink / raw) "Michael Erdmann" <michael.erdmann@snafu.de> wrote in message news:4586FAC4.2000003@snafu.de... > Brian May wrote: ... > > I would have thought since Install was defined within the generic > > unit, Install'Access would be OK. > > > > Or does Install'Access imply a temporary local variable? > > > > Put another way, how can you create a dangling pointer with > > Install'Access but not Install_Access? > > This is exactly what came into my mind when i was looking > at the offending code. Jean-Pierre explains it well. If you instantiate the generic inside a procedure, the access value could last longer than the procedure it points at. That's a no-no. Since generic bodies use "assume-the-worst" legality rules, it is illegal because it *might* happen. It should be noted that this rule dates back to Ada 95 (although it was poorly described in Ada 95). AI95-229 explains the issues, find it on www.ada-auth.org. Randy. ^ permalink raw reply [flat|nested] 19+ messages in thread
* [Revisited] How to get around "access type must not be outside generic unit" (was: How to get around "access type must not be outside generic unit") 2006-12-17 10:07 How to get around "access type must not be outside generic unit" Michael Erdmann 2006-12-17 12:45 ` Pascal Obry @ 2007-01-23 18:18 ` Dmitry A. Kazakov 2007-01-24 0:57 ` Randy Brukardt 1 sibling, 1 reply; 19+ messages in thread From: Dmitry A. Kazakov @ 2007-01-23 18:18 UTC (permalink / raw) On Sun, 17 Dec 2006 11:07:51 +0100, Michael Erdmann wrote: > after installing the latest version of GNAT on my linux box i encounter > a problem with old source code. The Fragment below shows the problem: > > ---- usage.ads > generic > type Data_Type is private; > package Usage is > > function Install return Boolean ; > procedure Doit( X : in out Data_Type ); > end Usage; > > ---- usage.adb > with Base; use Base; > > package body Usage is > > function Install return Boolean is > begin > return True; > end Install; > > procedure Doit( X : in out Data_Type ) is > begin > null; > end Doit; > > begin > Register("Doit", Install'Access); <<<< offending line > end Usage; I have some thought about it, and now I see it as a real problem. The use case I have in mind is binding to a C library. To consider is Register taking some access to a subprogram with C convention used to interface a some C library. This is a quite frequent pattern which now is broken, for a good reason BTW, because it was unsafe. Obviously Register cannot be touched. So the only solution is declaration of a local access type with a consequent Unchecked_Conversion on it: package body Usage is type Ptr is access function return Boolean; pragma Convention (C, Ptr); function To_Global is new Ada.Unchecked_Conversion (Ptr, C_Type_Of_Install); function Install return Boolean; pragma Convention (C, Install); function Install return Boolean is ... end Install; ... begin Register (..., To_Global (Install'Access); This is: 1. Ugly and error-prone 2. Defeats otherwise reasonable accessibility checks Potential solution: ------------------------ 1. Drop all accessibility checks for access to subprogram with pragma Convention (C, ...). Rationale: C subprograms are global 2. Prohibit pragma Convention (C, ...) in generic bodies for any subprogram types not mentioned in the specification AND in all local scopes. Rationale: any subprogram of C convention shall be library-level 3. Prohibit instantiation of generic units with pragma Convention (C, ...) used in specifications otherwise as at the library level. The result should be the package Usage required to be instantiated on library level, with Install exposed in the specification of. Explicit pragma Convention (C, ...) in the specification would reject instantiations without looking into bodies. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Revisited] How to get around "access type must not be outside generic unit" (was: How to get around "access type must not be outside generic unit") 2007-01-23 18:18 ` [Revisited] How to get around "access type must not be outside generic unit" (was: How to get around "access type must not be outside generic unit") Dmitry A. Kazakov @ 2007-01-24 0:57 ` Randy Brukardt 2007-01-24 11:42 ` [Revisited] How to get around "access type must not be outside generic unit" Dmitry A. Kazakov 0 siblings, 1 reply; 19+ messages in thread From: Randy Brukardt @ 2007-01-24 0:57 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:3vwf1b4b2ntl$.l9n17zmh9v8a$.dlg@40tude.net... ... > This is a quite frequent pattern which now is broken, for a good reason > BTW, because it was unsafe. Obviously Register cannot be touched. Well, the best solution is to touch Register, and give it an anonymous access type parameter (which doesn't do accessibility checks). Even better is to avoid C interfacing. ;-) > So the > only solution is declaration of a local access type with a consequent > Unchecked_Conversion on it: That won't work in a compiler that does generic code sharing (like Janus/Ada). Subprograms in a generic have an extra hidden parameter to carry the instance descriptor, and thus the profile doesn't match that of a routine outside of a generic. There is absoletely no way to change this inside of the generic body short of completely abandoning the code sharing model. .... > Potential solution: > ------------------------ > 1. Drop all accessibility checks for access to subprogram with > > pragma Convention (C, ...). > > Rationale: C subprograms are global Won't work in a generic code shared body. Also, it would cause problems if your C routine written in Ada did up-level accesses - you'd have all of the dangling pointer issues and no checks to prevent them. C routines absolutely have to be written at the library level. > 2. Prohibit pragma Convention (C, ...) in generic bodies for any subprogram > types not mentioned in the specification AND in all local scopes. That's already effectively true, since you can't do anything useful with it. But I don't know how this helps solve your problem. > 3. Prohibit instantiation of generic units with pragma Convention (C, ...) > used in specifications otherwise as at the library level. > > The result should be the package Usage required to be instantiated on > library level, with Install exposed in the specification of. Explicit > pragma Convention (C, ...) in the specification would reject instantiations > without looking into bodies. There isn't any reason to do this. It is trivial to write the specification of a generic so that it can only be instantiated at the library level. But in any case, the solution to your problem (as always) is to put the 'Access into the private part of the specification. Do that with an appropriate constant declaration. (If the parameter type of Register was anonymous, there is no problem, so there must be a named type that can be used.) Doing so will force the generic to be instantiated at the library level. So I don't see any problem with this example, and no Unchecked_Conversion. That is: > ---- usage.ads > generic > type Data_Type is private; > package Usage is > > function Install return Boolean ; > procedure Doit( X : in out Data_Type ); > private --- NEW Install_Access : constant Register_Sub_Type := Install'Access; -- New > end Usage; > > ---- usage.adb > with Base; use Base; > > package body Usage is > > function Install return Boolean is > begin > return True; > end Install; > > procedure Doit( X : in out Data_Type ) is > begin > null; > end Doit; > > begin > Register("Doit", Install_Access); -- Fine. > end Usage; And if the routine isn't declared in the spec, add it also to the private part. Randy. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Revisited] How to get around "access type must not be outside generic unit" 2007-01-24 0:57 ` Randy Brukardt @ 2007-01-24 11:42 ` Dmitry A. Kazakov 2007-01-24 11:58 ` Ludovic Brenta 2007-01-24 20:50 ` Randy Brukardt 0 siblings, 2 replies; 19+ messages in thread From: Dmitry A. Kazakov @ 2007-01-24 11:42 UTC (permalink / raw) On Tue, 23 Jan 2007 18:57:33 -0600, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:3vwf1b4b2ntl$.l9n17zmh9v8a$.dlg@40tude.net... > ... >> This is a quite frequent pattern which now is broken, for a good reason >> BTW, because it was unsafe. Obviously Register cannot be touched. > > Well, the best solution is to touch Register, and give it an anonymous > access type parameter (which doesn't do accessibility checks). Even better > is to avoid C interfacing. ;-) Let's take GtkAda as an example. The facts are: 1. It interfaces GTK+ (C++) 2. It is full of this package Glib is ... type Boxed_Copy is access function (Boxed : System.Address) return System.Address; pragma Convention (C, Boxed_Copy); type Boxed_Free is access procedure (Boxed : System.Address); pragma Convention (C, Boxed_Free); function Boxed_Type_Register_Static (Name : String; Copy : Boxed_Copy; Free : Boxed_Free) return GType; How can I (well, ACT (:-)) apply Convention (C,...) on an anonymous access type?! > That won't work in a compiler that does generic code sharing (like > Janus/Ada). Subprograms in a generic have an extra hidden parameter to carry > the instance descriptor, and thus the profile doesn't match that of a > routine outside of a generic. There is absoletely no way to change this > inside of the generic body short of completely abandoning the code sharing > model. And what Janus/Ada would do if it meets pragma Convention (C, Foo); ? >> Potential solution: >> ------------------------ >> 1. Drop all accessibility checks for access to subprogram with >> >> pragma Convention (C, ...). >> >> Rationale: C subprograms are global > > Won't work in a generic code shared body. Also, it would cause problems if > your C routine written in Ada did up-level accesses - you'd have all of the > dangling pointer issues and no checks to prevent them. C routines absolutely > have to be written at the library level. >> 2. Prohibit pragma Convention (C, ...) in generic bodies for any subprogram >> types not mentioned in the specification AND in all local scopes. > > That's already effectively true, since you can't do anything useful with it. > But I don't know how this helps solve your problem. > >> 3. Prohibit instantiation of generic units with pragma Convention (C, ...) >> used in specifications otherwise as at the library level. >> >> The result should be the package Usage required to be instantiated on >> library level, with Install exposed in the specification of. Explicit >> pragma Convention (C, ...) in the specification would reject instantiations >> without looking into bodies. > > There isn't any reason to do this. It is trivial to write the specification > of a generic so that it can only be instantiated at the library level. I meant (1 and 2 and 3), not (1 or 2 or 3)! (:-)) > But in any case, the solution to your problem (as always) is to put the > 'Access into the private part of the specification. Do that with an > appropriate constant declaration. (If the parameter type of Register was > anonymous, there is no problem, so there must be a named type that can be > used.) Doing so will force the generic to be instantiated at the library > level. OK, that's definitely better than Unchecked_Conversion. In Ada 95 it was enough to add a declaration of the subprogram to the specification, now we also need an access object. This is strange, at least not obvious. Why should it change anything? I mean, if it is semantically correct, then why the compiler cannot deduce it? Is it semantically correct? In the case with Glib above, would it be possible to instantiate a generic package in a local scope; call to Boxed_Type_Register_Static passing a constant as you described; and then leave the scope? generic package Foo is ... private function Copy (Boxed : System.Address) return System.Address; pragma Convention (C, Copy); procedure Free (Boxed : System.Address); pragma Convention (C, Free); Copy_Ptr : constant Boxed_Copy := Copy'Access; Free_Ptr : constant Boxed_Free := Free'Access; end Foo; package body Foo is function Copy (Boxed : System.Address) return System.Address is ... procedure Free (Boxed : System.Address) is ... ... begin ... := Boxed_Type_Register_Static ("Foo", Copy_Ptr, Free_Ptr); end Foo; ... declare My_Foo is new Foo; -- Is it legal in Ada 2005? begin ... end; -- Boom! -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Revisited] How to get around "access type must not be outside generic unit" 2007-01-24 11:42 ` [Revisited] How to get around "access type must not be outside generic unit" Dmitry A. Kazakov @ 2007-01-24 11:58 ` Ludovic Brenta 2007-01-24 13:46 ` Dmitry A. Kazakov 2007-01-24 20:50 ` Randy Brukardt 1 sibling, 1 reply; 19+ messages in thread From: Ludovic Brenta @ 2007-01-24 11:58 UTC (permalink / raw) Dmitry A. Kazakov writes: > Let's take GtkAda as an example. The facts are: > > 1. It interfaces GTK+ (C++) No, GTK+ is written in C, even though it implements an object-oriented design. > 2. It is full of this > > package Glib is > ... > type Boxed_Copy is access > function (Boxed : System.Address) return System.Address; > pragma Convention (C, Boxed_Copy); > type Boxed_Free is access procedure (Boxed : System.Address); > pragma Convention (C, Boxed_Free); > > function Boxed_Type_Register_Static > (Name : String; > Copy : Boxed_Copy; > Free : Boxed_Free) return GType; > > How can I (well, ACT (:-)) apply Convention (C,...) on an anonymous > access type?! These are named access types, AFAICT. GNAT implements access types with convention C as C pointers; by contrast, access types with convention Ada may carry dope information. -- Ludovic Brenta. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Revisited] How to get around "access type must not be outside generic unit" 2007-01-24 11:58 ` Ludovic Brenta @ 2007-01-24 13:46 ` Dmitry A. Kazakov 0 siblings, 0 replies; 19+ messages in thread From: Dmitry A. Kazakov @ 2007-01-24 13:46 UTC (permalink / raw) On Wed, 24 Jan 2007 12:58:59 +0100, Ludovic Brenta wrote: > Dmitry A. Kazakov writes: >> Let's take GtkAda as an example. The facts are: >> >> 1. It interfaces GTK+ (C++) > > No, GTK+ is written in C, even though it implements an object-oriented > design. Yes, or at least it has a pure C interface, no classes there. >> 2. It is full of this >> >> package Glib is >> ... >> type Boxed_Copy is access >> function (Boxed : System.Address) return System.Address; >> pragma Convention (C, Boxed_Copy); >> type Boxed_Free is access procedure (Boxed : System.Address); >> pragma Convention (C, Boxed_Free); >> >> function Boxed_Type_Register_Static >> (Name : String; >> Copy : Boxed_Copy; >> Free : Boxed_Free) return GType; >> >> How can I (well, ACT (:-)) apply Convention (C,...) on an anonymous >> access type?! > > These are named access types, AFAICT. Yes, and the first Randy's proposal was to change it to dreadful: function Boxed_Type_Register_Static ( Name : String; Copy : access function (Boxed : System.Address) return System.Address; Free : access procedure (Boxed : System.Address) ); My questions were: 1. How to apply pragma Convention on Copy and Free? 2. Why should this semantically change anything? > GNAT implements access types with convention C as C pointers; Sure. It would be silly to do otherwise. > by contrast, access types with > convention Ada may carry dope information. If you mean that dynamic accessibility checks might help here, then I doubt it. Boxed_Type_Register_Static is called from the body. It is too late to check anything. If a check should fail at run-time that would be even worse than any ugliest stuff, provided that were checked statically. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Revisited] How to get around "access type must not be outside generic unit" 2007-01-24 11:42 ` [Revisited] How to get around "access type must not be outside generic unit" Dmitry A. Kazakov 2007-01-24 11:58 ` Ludovic Brenta @ 2007-01-24 20:50 ` Randy Brukardt 2007-01-25 11:07 ` Dmitry A. Kazakov 1 sibling, 1 reply; 19+ messages in thread From: Randy Brukardt @ 2007-01-24 20:50 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1u2mhr9ypij4u.bn3yayn7o9l3$.dlg@40tude.net... ... > > That won't work in a compiler that does generic code sharing (like > > Janus/Ada). Subprograms in a generic have an extra hidden parameter to carry > > the instance descriptor, and thus the profile doesn't match that of a > > routine outside of a generic. There is absoletely no way to change this > > inside of the generic body short of completely abandoning the code sharing > > model. > > And what Janus/Ada would do if it meets pragma Convention (C, Foo); ? I'm not sure. Doesn't matter anyway, because you can't do anything with such a routine (as you are finding out). 'Access ensures that the profile is "correct"; it's got nothing to do with the Convention pragma on the subprogram. ... > > But in any case, the solution to your problem (as always) is to put the > > 'Access into the private part of the specification. Do that with an > > appropriate constant declaration. (If the parameter type of Register was > > anonymous, there is no problem, so there must be a named type that can be > > used.) Doing so will force the generic to be instantiated at the library > > level. > > OK, that's definitely better than Unchecked_Conversion. In Ada 95 it was > enough to add a declaration of the subprogram to the specification, now we > also need an access object. This is strange, at least not obvious. Why > should it change anything? Because it's part of the contract model. That is assume-the-best in the visible part of the spec, and assume-the-worst in the body. (We're somewhat confused about the private part.) Whenever we assume-the-best, there is a required recheck in the instance. Thus, putting such a 'Access in the spec means that it will be rechecked and rejected if it causes trouble. In this case, that means that the generic will be rejected if it is instantiated in a nested scope. > I mean, if it is semantically correct, then why > the compiler cannot deduce it? Is it semantically correct? In the case with > Glib above, would it be possible to instantiate a generic package in a > local scope; call to Boxed_Type_Register_Static passing a constant as you > described; and then leave the scope? No, the instance will be rejected at compile-time as failing an accessibility check. In terms of the shared implementation, what happens is that the instance makes a wrapper for the routine with the "correct" profile for 'access. You can't do that in the body when sharing, because you always need the instance descriptor parameter there. In spec, you can do it both ways to allow calling from both the internal and external views. That's because you know where the instance descriptor is for the particular instance, and can include it in the wrapper call. Randy. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [Revisited] How to get around "access type must not be outside generic unit" 2007-01-24 20:50 ` Randy Brukardt @ 2007-01-25 11:07 ` Dmitry A. Kazakov 0 siblings, 0 replies; 19+ messages in thread From: Dmitry A. Kazakov @ 2007-01-25 11:07 UTC (permalink / raw) On Wed, 24 Jan 2007 14:50:49 -0600, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1u2mhr9ypij4u.bn3yayn7o9l3$.dlg@40tude.net... > ... >>> But in any case, the solution to your problem (as always) is to put the >>> 'Access into the private part of the specification. Do that with an >>> appropriate constant declaration. (If the parameter type of Register was >>> anonymous, there is no problem, so there must be a named type that can be >>> used.) Doing so will force the generic to be instantiated at the library >>> level. >> >> OK, that's definitely better than Unchecked_Conversion. In Ada 95 it was >> enough to add a declaration of the subprogram to the specification, now we >> also need an access object. This is strange, at least not obvious. Why >> should it change anything? > > Because it's part of the contract model. > > That is assume-the-best in the > visible part of the spec, and assume-the-worst in the body. (We're somewhat > confused about the private part.) Whenever we assume-the-best, there is a > required recheck in the instance. > > Thus, putting such a 'Access in the spec means that it will be rechecked and > rejected if it causes trouble. In this case, that means that the generic > will be rejected if it is instantiated in a nested scope. Hmm, I don't think it is a contract. To be a contract "I want X'Access" should be in the generic formal part. It is closer to how C++ templates work. (for "I want X'Access" there even exists a reserved keyword) But that's no matter. >> I mean, if it is semantically correct, then why >> the compiler cannot deduce it? Is it semantically correct? In the case with >> Glib above, would it be possible to instantiate a generic package in a >> local scope; call to Boxed_Type_Register_Static passing a constant as you >> described; and then leave the scope? > > No, the instance will be rejected at compile-time as failing an > accessibility check. [...] I see, thank you for explanation. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2007-01-25 11:07 UTC | newest] Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2006-12-17 10:07 How to get around "access type must not be outside generic unit" Michael Erdmann 2006-12-17 12:45 ` Pascal Obry 2006-12-17 14:28 ` Michael Erdmann 2006-12-17 15:53 ` Pascal Obry 2006-12-17 20:49 ` Robert A Duff 2006-12-18 3:35 ` Brian May 2006-12-18 7:49 ` Jean-Pierre Rosen 2006-12-18 23:15 ` Brian May 2006-12-19 1:48 ` Randy Brukardt 2006-12-19 7:41 ` Jean-Pierre Rosen 2006-12-18 20:32 ` Michael Erdmann 2006-12-18 20:57 ` Randy Brukardt 2007-01-23 18:18 ` [Revisited] How to get around "access type must not be outside generic unit" (was: How to get around "access type must not be outside generic unit") Dmitry A. Kazakov 2007-01-24 0:57 ` Randy Brukardt 2007-01-24 11:42 ` [Revisited] How to get around "access type must not be outside generic unit" Dmitry A. Kazakov 2007-01-24 11:58 ` Ludovic Brenta 2007-01-24 13:46 ` Dmitry A. Kazakov 2007-01-24 20:50 ` Randy Brukardt 2007-01-25 11:07 ` Dmitry A. Kazakov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox