comp.lang.ada
 help / color / mirror / Atom feed
* 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  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

* 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

* [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