comp.lang.ada
 help / color / mirror / Atom feed
* Elaboration in generic package
@ 2017-04-12 19:30 Simon Wright
  2017-04-12 22:29 ` Randy Brukardt
  2017-04-13 15:38 ` marciant
  0 siblings, 2 replies; 4+ messages in thread
From: Simon Wright @ 2017-04-12 19:30 UTC (permalink / raw)


A StackOverflow user raises this problem
(http://stackoverflow.com/q/43349462/40851). The code:

   generic
      Top_M : Positive;
   package Mystic is
      type T is private;
      procedure Info;
   private
       type Table is array (Positive range <>) of Positive;
       function reallyComplicatedFunction(x : Positive) return Table;

       mytable : constant Table := reallyComplicatedFunction(top_m); --<<<<<
       -- I will need mytable for calculations later

       type T is array (mytable'Range) of Natural;
       -- T is very different from Table, except they share their Range
   end Mystic;

They wonder how the call to reallyComplicatedFunction at line 10
succeeds, given it looks like its body hasn't been seen yet (ARM
3.11(10)). Indeed, if I make Mystic non-generic (Top_M is a constant)
GNAT tells me

kryptozoon.ada:12:33: warning: cannot call "reallyComplicatedFunction" before body seen
kryptozoon.ada:12:33: warning: Program_Error will be raised at run time

and then, sure enough,

raised PROGRAM_ERROR : kryptozoon.ada:12 access before elaboration

Is it possible that the answer is ARM 3.11(13), "For the instantiation
of a generic unit that has a body, a check is made that this body is
already elaborated."? If so, this seems surprising.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Elaboration in generic package
  2017-04-12 19:30 Elaboration in generic package Simon Wright
@ 2017-04-12 22:29 ` Randy Brukardt
  2017-04-13  7:19   ` Simon Wright
  2017-04-13 15:38 ` marciant
  1 sibling, 1 reply; 4+ messages in thread
From: Randy Brukardt @ 2017-04-12 22:29 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:ly60i9bf06.fsf@pushface.org...
>A StackOverflow user raises this problem
> (http://stackoverflow.com/q/43349462/40851). The code:
>
>   generic
>      Top_M : Positive;
>   package Mystic is
>      type T is private;
>      procedure Info;
>   private
>       type Table is array (Positive range <>) of Positive;
>       function reallyComplicatedFunction(x : Positive) return Table;
>
>       mytable : constant Table := 
> reallyComplicatedFunction(top_m); --<<<<<
>       -- I will need mytable for calculations later
>
>       type T is array (mytable'Range) of Natural;
>       -- T is very different from Table, except they share their Range
>   end Mystic;
>
> They wonder how the call to reallyComplicatedFunction at line 10
> succeeds, given it looks like its body hasn't been seen yet (ARM
> 3.11(10)). Indeed, if I make Mystic non-generic (Top_M is a constant)
> GNAT tells me
>
> kryptozoon.ada:12:33: warning: cannot call "reallyComplicatedFunction" 
> before body seen
> kryptozoon.ada:12:33: warning: Program_Error will be raised at run time
>
> and then, sure enough,
>
> raised PROGRAM_ERROR : kryptozoon.ada:12 access before elaboration
>
> Is it possible that the answer is ARM 3.11(13), "For the instantiation
> of a generic unit that has a body, a check is made that this body is
> already elaborated."? If so, this seems surprising.

Thoughts, not answers:

(1) GNAT doesn't follow the RM vis-a-vis elaboration checks unless -gnatE is 
used, so unless that it is the case, there's really nothing to talk about. 
The RM has nothing to say really about non-standard modes.

(2) 3.11(10) and 3.11(13) are independent checks; I don't see anything that 
suggests that making the one check eliminates the other.

(3) There are other cases where there are multiple elaboration checks 
(AI95-00064-1 discusses one such case).

So my gut feeling is that there should be an elaboration check (and 
hopefully a warning that the check will always fail). That suggests that the 
OP has found a compiler bug, nothing more.

OTOH, I remember spending quite a bit of effort eliminating elaboration 
checks in cases where they could not fail. So I may have forgotten 
something.

                  Randy.

P.S. On second thought, it seems necessary to have an elaboration check in 
this case, since the body could depend on something not elaborated at the 
point of call. For instance:

with My_Random;
package body Mystic is

    Seed : Natural := My_Random; -- A function call.

     function reallyComplicatedFunction (TM : Positive) return Table is
     begin
          if TM > Seed then -- Oops!
              ...
          end if;
     end reallyComplicatedFunction;

end Mystic;

Since Ada elaborates items linearly, the instance elaboration of Mystic will 
call reallyComplicatedFunction before Seed is elaborated -- meaning the body 
would be depending on something uninitialized. That's what subprogram 
elaboration checks are designed to prevent. Ergo, there must be a check in 
this case (regardless of the actual body, of course). (The generic body 
check is something different; it makes sure that the objects that the body 
can reference are elaborated before the instance of the body is elaborated. 
For "normal" packages, that is done statically by the rules for with 
clauses, but a generic unit is different in that regard.)

                                  Randy.



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Elaboration in generic package
  2017-04-12 22:29 ` Randy Brukardt
@ 2017-04-13  7:19   ` Simon Wright
  0 siblings, 0 replies; 4+ messages in thread
From: Simon Wright @ 2017-04-13  7:19 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:

> Since Ada elaborates items linearly, the instance elaboration of
> Mystic will call reallyComplicatedFunction before Seed is elaborated
> -- meaning the body would be depending on something
> uninitialized. That's what subprogram elaboration checks are designed
> to prevent. Ergo, there must be a check in this case (regardless of
> the actual body, of course).

I tried this simple demo

   package body Mystic is
      Max : Positive;
      function reallyComplicatedFunction(x : Positive) return Table is
         Result : Table (1 .. Positive'Min (X, Max) / 2) := (others => 1);
      begin
         return Result;
      end ReallyComplicatedFunction;
   begin
      Max := 5;
   end Mystic;

and, surprise, the value of Max used is 0; no warnings, no ABE, even
with -gnatE. Bug report forthcoming.

Thanks for the analysis.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: Elaboration in generic package
  2017-04-12 19:30 Elaboration in generic package Simon Wright
  2017-04-12 22:29 ` Randy Brukardt
@ 2017-04-13 15:38 ` marciant
  1 sibling, 0 replies; 4+ messages in thread
From: marciant @ 2017-04-13 15:38 UTC (permalink / raw)


IANALL (I am not a language lawyer :)

> They wonder how the call to reallyComplicatedFunction at line 10
> succeeds, given it looks like its body hasn't been seen yet (ARM
> 3.11(10)).

The executable code "comes to life" at instantiation.  So if

> ... ARM 3.11(13), "For the instantiation of a generic unit 
> that has a body, a check is made that this body is already elaborated."

is an 'is this elaboration of an instance legal' check then the body
is always available and therefore the call toi complicated function will
succeed. 

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-04-13 15:38 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-12 19:30 Elaboration in generic package Simon Wright
2017-04-12 22:29 ` Randy Brukardt
2017-04-13  7:19   ` Simon Wright
2017-04-13 15:38 ` marciant

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox