comp.lang.ada
 help / color / mirror / Atom feed
* Containers, dangling references
@ 2020-03-09 16:43 Simon Wright
  2020-03-09 23:19 ` Randy Brukardt
  0 siblings, 1 reply; 4+ messages in thread
From: Simon Wright @ 2020-03-09 16:43 UTC (permalink / raw)


I've been working on checking the upcoming FSF GCC 10 against existing
projects.

One case is a set of containers which include reference types (which,
under the hood, support for example the "for all X of Y" iteration
style).

The original version of the code looked like

   type Reference_Type
     (Element : not null access Element_Type)
      is record
         Dummy : Integer := raise Program_Error with "uninitialized reference";
      end record;

(this is the full declaration; Dummy is there so that default
initialization will raise PE, as required, e.g. ARM A.18.2(147.4)).

   function Reference
     (C :aliased in out Container; Position : in Cursor)
     return Reference_Type;

with implementation

   function Reference (C : aliased in out Container; Position : in Cursor)
                      return Reference_Type
   is
      pragma Unreferenced (C);
   begin
      return (Element => Position.The_Node.all.The_Element'Access, Dummy => 1);
   end Reference;

which was fine with compilers up to FSF GCC 9, GNAT CE 2019. With GCC
10, we get

   references.adb:8:26: access discriminant in return aggregate would be
   a dangling reference

I was a bit puzzled by the Position.The_Node.all.The_Element'Access -
why the .all? It turns out that if you remove it, the compilers that
were happy are no longer. Perhaps this was some circuitry in GNAT to
suppress this error?

How do the Ada.Containers manage this? It turns out that GNAT's
version is more like

      return R : constant Reference_Type :=
        (Element => Position.The_Node.The_Element'Access, Dummy => 1)
      do
         null;
      end return;

and this is fine in GCC 10 (but if you put in the .all the error
message returns).

I found where the error message is raised[1], but it's hard to tell
what the compiler is actually checking for.

[1] https://github.com/gcc-mirror/gcc/blob/master/gcc/ada/sem_ch6.adb#L858

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

* Re: Containers, dangling references
  2020-03-09 16:43 Containers, dangling references Simon Wright
@ 2020-03-09 23:19 ` Randy Brukardt
  2020-03-10 18:07   ` Simon Wright
  0 siblings, 1 reply; 4+ messages in thread
From: Randy Brukardt @ 2020-03-09 23:19 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:lya74pbhro.fsf@pushface.org...
...
> with implementation
>
>   function Reference (C : aliased in out Container; Position : in Cursor)
>                      return Reference_Type
>   is
>      pragma Unreferenced (C);
>   begin
>      return (Element => Position.The_Node.all.The_Element'Access, Dummy => 
> 1);
>   end Reference;

The language rules are designed to allow returning part of an aliased 
parameter as the return from a function. But one could also return a part of 
the designated object of a library-level access type.

Thus, what matters here is the type declaration of "The_Node", which would 
need to be a library-level access type (or at least instance-level) in order 
of this to work.

I note this implementation is missing the check that the cursor is for an 
element in the provided container (and isn't null). Perhaps you simplified 
the implementation for this presentation.

This sort of expression is a tough one to deal with for compilers. Janus/Ada 
used to (and maybe still does :-) have problems with the accessibility of 
expressions that have multiple access types. It would use the wrong type to 
determine the accessibility. Perhaps something similar is happening for 
GNAT. It's also suspicious that the explicit .all changes the result from 
the implicit .all. That suggests a bug more than an intended implementation.

                               Randy.


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

* Re: Containers, dangling references
  2020-03-09 23:19 ` Randy Brukardt
@ 2020-03-10 18:07   ` Simon Wright
  2020-03-10 20:28     ` Randy Brukardt
  0 siblings, 1 reply; 4+ messages in thread
From: Simon Wright @ 2020-03-10 18:07 UTC (permalink / raw)


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

> "Simon Wright" <simon@pushface.org> wrote in message 
> news:lya74pbhro.fsf@pushface.org...
> ...
>> with implementation
>>
>>   function Reference (C : aliased in out Container; Position : in Cursor)
>>                      return Reference_Type
>>   is
>>      pragma Unreferenced (C);
>>   begin
>>      return (Element => Position.The_Node.all.The_Element'Access, Dummy => 
>> 1);
>>   end Reference;
>
> The language rules are designed to allow returning part of an aliased
> parameter as the return from a function. But one could also return a
> part of the designated object of a library-level access type.

Is there any difference between an ordinary return & an extended return?
Looking at AARM 6.5(5.8/3), I think not?

> Thus, what matters here is the type declaration of "The_Node", which
> would need to be a library-level access type (or at least
> instance-level) in order of this to work.

There are all at library level.

   type Node_Type is limited record
      The_Element : aliased Element_Type;
   end record;
   type Node_Access is access Node_Type;

   type Container is tagged record
      A_Node : Node_Access;
   end record;
   type Container_Access is access all Container;

   type Cursor is record
      The_Container : Container_Access;
      The_Node : Node_Access;
   end record;

> I note this implementation is missing the check that the cursor is for
> an element in the provided container (and isn't null). Perhaps you
> simplified the implementation for this presentation.

A mixture of this and an incomplete original implementation.

> This sort of expression is a tough one to deal with for
> compilers. Janus/Ada used to (and maybe still does :-) have problems
> with the accessibility of expressions that have multiple access
> types. It would use the wrong type to determine the
> accessibility. Perhaps something similar is happening for GNAT. It's
> also suspicious that the explicit .all changes the result from the
> implicit .all. That suggests a bug more than an intended
> implementation.

That's what I thought.

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

* Re: Containers, dangling references
  2020-03-10 18:07   ` Simon Wright
@ 2020-03-10 20:28     ` Randy Brukardt
  0 siblings, 0 replies; 4+ messages in thread
From: Randy Brukardt @ 2020-03-10 20:28 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:ly5zfcaxsy.fsf@pushface.org...
> "Randy Brukardt" <randy@rrsoftware.com> writes:
...
>> The language rules are designed to allow returning part of an aliased
>> parameter as the return from a function. But one could also return a
>> part of the designated object of a library-level access type.
>
> Is there any difference between an ordinary return & an extended return?
> Looking at AARM 6.5(5.8/3), I think not?

Should not matter. We want it to be easily possible to replace one with the 
other, since it often happens that one needs to do more (or less) during a 
return when maintaining a function.

                 Randy.


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

end of thread, other threads:[~2020-03-10 20:28 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-09 16:43 Containers, dangling references Simon Wright
2020-03-09 23:19 ` Randy Brukardt
2020-03-10 18:07   ` Simon Wright
2020-03-10 20:28     ` Randy Brukardt

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