comp.lang.ada
 help / color / mirror / Atom feed
* GCC 11 bug? lawyer needed
@ 2021-05-03 16:08 Simon Wright
  2021-05-05  3:54 ` Randy Brukardt
  0 siblings, 1 reply; 10+ messages in thread
From: Simon Wright @ 2021-05-03 16:08 UTC (permalink / raw)


This code results in the error shown:

     1. package Aliased_Tagged_Types is
     2.
     3.    type T is tagged null record;
     4.
     5.    function P (Param : aliased T) return Boolean
     6.      is (False);
     7.
     8.    function F (Param : T) return Boolean
     9.      is (Param.P);
                 |
        >>> actual for explicitly aliased formal is too short lived

    10.
    11. end Aliased_Tagged_Types;

The compiler code that results in this error is at sem_ch4.adb:1490, and
was introduced for Ada202x accessibiity checking reasons.

   --  Check whether the formal is aliased and if the accessibility
   --  level of the actual is deeper than the accessibility level
   --  of the enclosing subprogam to which the current return
   --  statement applies.

   [...]

   if Is_Explicitly_Aliased (Form)
     and then Is_Entity_Name (Act)
     and then Static_Accessibility_Level
                (Act, Zero_On_Dynamic_Level)
                  > Subprogram_Access_Level (Current_Subprogram)
   then
      Error_Msg_N ("actual for explicitly aliased formal is too"
                    & " short lived", Act);
   end if;

----

For those interested, this issue affects Alire.

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

* Re: GCC 11 bug? lawyer needed
  2021-05-03 16:08 GCC 11 bug? lawyer needed Simon Wright
@ 2021-05-05  3:54 ` Randy Brukardt
  2021-05-05 10:01   ` AdaMagica
  0 siblings, 1 reply; 10+ messages in thread
From: Randy Brukardt @ 2021-05-05  3:54 UTC (permalink / raw)


We spent a lot of time and effort in the ARG talking about this case (see 
AI12-0402-1). The Ada 2012 RM does indeed say this case is illegal. The 
reason is that aliased parameters are designed so that one can return part 
of of them in the return object of the function. And a normal parameter is 
assumed to be local (since its accessibility is unknown) - that means it is 
too local for an aliased parameter of a function that is used in some 
non-local way (including being returned from a non-local function).

However, since one cannot return a part of a parameter for a function that 
returns an elementary type (other than anonymous access returns, which have 
special rules anyway), we added an exception to the rules for that case in 
Ada 202x. (We tried a number of more liberal exceptions, but they were 
complex and had [unlikely] holes.) So the most current rule is that the call 
of P is legal.

That wasn't decided until the December ARG meeting, so it happened after the 
GNATPro 21 release (and I expect that the GNAT CE is derived from that 
version). And I'd guess that in Ada 2012 mode, this check would remain as it 
is (the change was not made retroactively - not sure why).

                             Randy.

"Simon Wright" <simon@pushface.org> wrote in message 
news:lyh7jjztor.fsf@pushface.org...
> This code results in the error shown:
>
>     1. package Aliased_Tagged_Types is
>     2.
>     3.    type T is tagged null record;
>     4.
>     5.    function P (Param : aliased T) return Boolean
>     6.      is (False);
>     7.
>     8.    function F (Param : T) return Boolean
>     9.      is (Param.P);
>                 |
>        >>> actual for explicitly aliased formal is too short lived
>
>    10.
>    11. end Aliased_Tagged_Types;
>
> The compiler code that results in this error is at sem_ch4.adb:1490, and
> was introduced for Ada202x accessibiity checking reasons.
>
>   --  Check whether the formal is aliased and if the accessibility
>   --  level of the actual is deeper than the accessibility level
>   --  of the enclosing subprogam to which the current return
>   --  statement applies.
>
>   [...]
>
>   if Is_Explicitly_Aliased (Form)
>     and then Is_Entity_Name (Act)
>     and then Static_Accessibility_Level
>                (Act, Zero_On_Dynamic_Level)
>                  > Subprogram_Access_Level (Current_Subprogram)
>   then
>      Error_Msg_N ("actual for explicitly aliased formal is too"
>                    & " short lived", Act);
>   end if;
>
> ----
>
> For those interested, this issue affects Alire. 


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

* Re: GCC 11 bug? lawyer needed
  2021-05-05  3:54 ` Randy Brukardt
@ 2021-05-05 10:01   ` AdaMagica
  2021-05-05 16:10     ` AdaMagica
  0 siblings, 1 reply; 10+ messages in thread
From: AdaMagica @ 2021-05-05 10:01 UTC (permalink / raw)


Randy Brukardt schrieb am Mittwoch, 5. Mai 2021 um 05:54:46 UTC+2:
> And a normal parameter is assumed to be local (since its accessibility is unknown) - that means it is
> too local for an aliased parameter of a function that is used in some non-local way 

RM 3.10(9/3): Finally, a formal parameter or generic formal object of a tagged type is defined to be aliased.
RM 6.4.1(6/3): If the formal parameter is an explicitly aliased parameter, the type of the actual parameter shall be tagged or the actual parameter shall be an aliased view of an object.
Both of these conditions are fulfilled here.
There are many more places about explicitly aliased parameters in the RM. I've read them all. It left me wondering.

I do not see what aliasing a tagged parameter buys. A parameter of a tagged typed  is aliased per se, or do I misread the RM.
I'm having big problems trying to understand the RM.
I will try to grock the AI.

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

* Re: GCC 11 bug? lawyer needed
  2021-05-05 10:01   ` AdaMagica
@ 2021-05-05 16:10     ` AdaMagica
  2021-05-06  0:39       ` Randy Brukardt
  0 siblings, 1 reply; 10+ messages in thread
From: AdaMagica @ 2021-05-05 16:10 UTC (permalink / raw)


AdaMagica schrieb am Mittwoch, 5. Mai 2021 um 12:01:07 UTC+2:
> I will try to grock the AI.
Hm, I'm still confused. Can anyone please come up with some examples that explain what this is all about?

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

* Re: GCC 11 bug? lawyer needed
  2021-05-05 16:10     ` AdaMagica
@ 2021-05-06  0:39       ` Randy Brukardt
  2021-05-06 13:07         ` AdaMagica
  2021-05-06 20:02         ` Simon Wright
  0 siblings, 2 replies; 10+ messages in thread
From: Randy Brukardt @ 2021-05-06  0:39 UTC (permalink / raw)


"AdaMagica" <christ-usch.grein@t-online.de> wrote in message 
news:aaa58296-3298-4b70-ac7e-1393f579f217n@googlegroups.com...
> AdaMagica schrieb am Mittwoch, 5. Mai 2021 um 12:01:07 UTC+2:
>> I will try to grock the AI.
> Hm, I'm still confused. Can anyone please come up with some examples that 
> explain what this is all about?

See 6.4.1(6/3): there is an accessibility check on the actual parameter of 
an aliased parameter. This allows an aliased parameter to have the 
accessibility of the return object of a function, rather than local 
accessibility. There's a bunch of rules in 3.10.2 that combine to have the 
right effect.

You see the result in an operation like "Reference" in the containers. If 
you have:

     function Foo (A : in out Container; Idx : in Natural) return access 
Element;

then an implementation of:

     function Foo (A : in out Container) return access Element is
     begin
          return A.Data(Idx)'Access; -- (1)
     end Foo;

(1) is illegal, as A has local to Foo accessibility, while the anonymous 
access has the accessibility of the return object (the point of call), which 
is necessarily outside of Foo.

You can change (1) to:
          return A.Data(Idx)'Unchecked_Access; -- (1)
but now you can create a dangling pointer, for instance if Foo is assigned 
to a library-level access type and the actual for A is not library-level.

But you can change the parameter to "aliased", then the accessibility check 
is moved to the call site (where it must always suceeed for the vast 
majority of calls). There's no accessibility check at (1) in that case 
(which could be at best a dynamic check, which is a correctness hazard, and 
also has an overhead cost). And you still have the safety of not being able 
to create a dangling pointer.

It is a bit weird that this property is tied to "aliased" parameters. This 
property came first, and we discussed the syntax to use for a long time. 
Eventually it was decided to call them "aliased" parameters, but of course 
that meant it was necessary to generalize the usages.

This special rule does have the downside of being able to fail in some safe 
cases, like the one noted by the OP. That doesn't happen for procedures, 
since aliased parameters have no special semantics for procedures. We 
decided to remove the special semantics for functions for which it is 
impossible to return a part of the parameter (that is, any 
elementary-returning function), as that special semantics provides no 
benefit in such a case (but it does have a cost).

I agree that the original author of that program should not have used 
"aliased" in the way that they did (they don't need the special semantics), 
but we realize that some people would prefer to *explicitly* mark things as 
aliased when they are going to take 'Access (and not worry about the type of 
the parameter -- after all, it could change). That is, they don't want to 
depend on the implicit behavior of tagged types -- or perhaps they don't 
even know about it. Which leads to the problem that occurs here, as 
"aliased" has slightly different meanings for functions (now just composite 
functions) and procedures.

Since this is real code that didn't work as expected, it seemed to make 
sense to reduce the problem with a minor language tweak.

                                   Randy.




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

* Re: GCC 11 bug? lawyer needed
  2021-05-06  0:39       ` Randy Brukardt
@ 2021-05-06 13:07         ` AdaMagica
  2021-05-06 20:02         ` Simon Wright
  1 sibling, 0 replies; 10+ messages in thread
From: AdaMagica @ 2021-05-06 13:07 UTC (permalink / raw)


Thank you, Randy, for the nice explanation. There're still some hazy places, but I begin to see the big picture.
Christoph

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

* Re: GCC 11 bug? lawyer needed
  2021-05-06  0:39       ` Randy Brukardt
  2021-05-06 13:07         ` AdaMagica
@ 2021-05-06 20:02         ` Simon Wright
  2021-05-06 20:51           ` Dmitry A. Kazakov
  2021-05-06 23:59           ` Randy Brukardt
  1 sibling, 2 replies; 10+ messages in thread
From: Simon Wright @ 2021-05-06 20:02 UTC (permalink / raw)


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

> I agree that the original author of that program should not have used 
> "aliased" in the way that they did (they don't need the special semantics), 
> but we realize that some people would prefer to *explicitly* mark things as 
> aliased when they are going to take 'Access (and not worry about the type of 
> the parameter -- after all, it could change). That is, they don't want to 
> depend on the implicit behavior of tagged types -- or perhaps they don't 
> even know about it. Which leads to the problem that occurs here, as 
> "aliased" has slightly different meanings for functions (now just composite 
> functions) and procedures.

The original code, from the Alire project, had (I've edited it slightly)

   package Holders
   is new Ada.Containers.Indefinite_Holders (Node'Class);

   type Tree is
     new Holders.Holder
     and ...

   function Root (This : Tree) return Node'Class is
     (This.Constant_Reference);

where that Constant_Reference is inherited (eventually) from
Ada.Containers.Indefinite_Holders.Holder,

   function Constant_Reference
     (Container : aliased Holder) return Constant_Reference_Type;
   pragma Inline (Constant_Reference);

Shame it had to be there.

I've just tried splattering 'aliased' wherever the compiler told me it
was needed; it's now spreading into other packages. Ugh.

The solution might just be using composition rather than inheritance.

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

* Re: GCC 11 bug? lawyer needed
  2021-05-06 20:02         ` Simon Wright
@ 2021-05-06 20:51           ` Dmitry A. Kazakov
  2021-05-06 23:59           ` Randy Brukardt
  1 sibling, 0 replies; 10+ messages in thread
From: Dmitry A. Kazakov @ 2021-05-06 20:51 UTC (permalink / raw)


On 2021-05-06 22:02, Simon Wright wrote:
> "Randy Brukardt" <randy@rrsoftware.com> writes:
> 
>> I agree that the original author of that program should not have used
>> "aliased" in the way that they did (they don't need the special semantics),
>> but we realize that some people would prefer to *explicitly* mark things as
>> aliased when they are going to take 'Access (and not worry about the type of
>> the parameter -- after all, it could change). That is, they don't want to
>> depend on the implicit behavior of tagged types -- or perhaps they don't
>> even know about it. Which leads to the problem that occurs here, as
>> "aliased" has slightly different meanings for functions (now just composite
>> functions) and procedures.
> 
> The original code, from the Alire project, had (I've edited it slightly)
> 
>     package Holders
>     is new Ada.Containers.Indefinite_Holders (Node'Class);
> 
>     type Tree is
>       new Holders.Holder
>       and ...
> 
>     function Root (This : Tree) return Node'Class is
>       (This.Constant_Reference);
> 
> where that Constant_Reference is inherited (eventually) from
> Ada.Containers.Indefinite_Holders.Holder,
> 
>     function Constant_Reference
>       (Container : aliased Holder) return Constant_Reference_Type;
>     pragma Inline (Constant_Reference);
> 
> Shame it had to be there.
> 
> I've just tried splattering 'aliased' wherever the compiler told me it
> was needed; it's now spreading into other packages. Ugh.
> 
> The solution might just be using composition rather than inheritance.

In my experience mixing handles with target types does not work anyway 
regardless accessibility rules mess.

I tend to use interfaces instead:

    type Abstract_Node_Interface is interface ...;

Then both the handle and the target type implement 
Abstract_Node_Interface. The target type goes into hiding, the client 
need not to see it.

This requires manual delegation in all primitive operations of handles: 
dereference + call. But in the end it pays off. Especially with trees, 
because in mutator operations I can check the reference count of the 
node and choose to clone it (and maybe the subtree) if there are 
multiple external handles to it.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

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

* Re: GCC 11 bug? lawyer needed
  2021-05-06 20:02         ` Simon Wright
  2021-05-06 20:51           ` Dmitry A. Kazakov
@ 2021-05-06 23:59           ` Randy Brukardt
  2021-05-08 10:17             ` Simon Wright
  1 sibling, 1 reply; 10+ messages in thread
From: Randy Brukardt @ 2021-05-06 23:59 UTC (permalink / raw)


"Simon Wright" <simon@pushface.org> wrote in message 
news:lylf8ry6j5.fsf@pushface.org...
> "Randy Brukardt" <randy@rrsoftware.com> writes:
>
>> I agree that the original author of that program should not have used
>> "aliased" in the way that they did (they don't need the special 
>> semantics),
>> but we realize that some people would prefer to *explicitly* mark things 
>> as
>> aliased when they are going to take 'Access (and not worry about the type 
>> of
>> the parameter -- after all, it could change). That is, they don't want to
>> depend on the implicit behavior of tagged types -- or perhaps they don't
>> even know about it. Which leads to the problem that occurs here, as
>> "aliased" has slightly different meanings for functions (now just 
>> composite
>> functions) and procedures.
>
> The original code, from the Alire project, had (I've edited it slightly)
>
>   package Holders
>   is new Ada.Containers.Indefinite_Holders (Node'Class);
>
>   type Tree is
>     new Holders.Holder
>     and ...
>
>   function Root (This : Tree) return Node'Class is
>     (This.Constant_Reference);
>
> where that Constant_Reference is inherited (eventually) from
> Ada.Containers.Indefinite_Holders.Holder,
>
>   function Constant_Reference
>     (Container : aliased Holder) return Constant_Reference_Type;
>   pragma Inline (Constant_Reference);
>
> Shame it had to be there.

Constant_Reference is the case for which these semantics was designed. Hard 
to avoid it there. ;-)

Note that by returning Node'Class rather than an elementary type, you don't 
get to use the new rule tweak. Since all tagged types are by-reference (not 
by copy), the "Root" routine has to return the object that it has, which 
ultimately is part of Tree. So you actually need "aliased" on Root, since 
you are (ultimately) returning a part of the formal parameter (and which 
could become dangling if you pass in an object which is too local).

> I've just tried splattering 'aliased' wherever the compiler told me it
> was needed; it's now spreading into other packages. Ugh.

I think you need to make a copy of the return object somewhere; the obvious 
answer is to replace function Constant_Reference with function Element. Of 
course, if the return object is large enough, that could be expensive. (That 
doesn't work if you want to write the node, but the use of 
Constant_Reference doesn't allow that anyway, so in this case it doesn't 
matter.)

> The solution might just be using composition rather than inheritance.

Yeah, or using handles more as Dmitry says. In any case, it seems like some 
redesign is necessary.

                  Randy.


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

* Re: GCC 11 bug? lawyer needed
  2021-05-06 23:59           ` Randy Brukardt
@ 2021-05-08 10:17             ` Simon Wright
  0 siblings, 0 replies; 10+ messages in thread
From: Simon Wright @ 2021-05-08 10:17 UTC (permalink / raw)


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

> I think you need to make a copy of the return object somewhere; the
> obvious answer is to replace function Constant_Reference with function
> Element.

That appears to be a fine workround! Thanks!

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

end of thread, other threads:[~2021-05-08 10:17 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-03 16:08 GCC 11 bug? lawyer needed Simon Wright
2021-05-05  3:54 ` Randy Brukardt
2021-05-05 10:01   ` AdaMagica
2021-05-05 16:10     ` AdaMagica
2021-05-06  0:39       ` Randy Brukardt
2021-05-06 13:07         ` AdaMagica
2021-05-06 20:02         ` Simon Wright
2021-05-06 20:51           ` Dmitry A. Kazakov
2021-05-06 23:59           ` Randy Brukardt
2021-05-08 10:17             ` Simon Wright

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