Version 1.2 of ai22s/ai22-0026-1.txt

Unformatted version of ai22s/ai22-0026-1.txt version 1.2
Other versions for file ai22s/ai22-0026-1.txt

!standard 4.8(10.1/3)          22-01-21 AI22-0026-1/01
!class binding interpretation 22-01-21
!status work item 22-01-21
!status received 22-01-21
!priority Low
!difficulty Easy
!qualifier Omission
!subject Problem with nested type extension check
!summary
An allocator for an anonymous access return type which designates a tagged type needs to make an accessibility check to ensure that the designated object's type lives at least as long as the result type.
!issue
The following test case which illustrates a way that you can, by conversion, create an access-to-class-wide value that designates an object of a tag is shorter-lived than the access-to-class-wide type:
type CCAccess is access all C'Class;
function Nasty(N : Integer) return CCAccess is type D is new C with null record;
function NastyAllocator return access D is begin return new D'(null record); end NastyAllocator;
begin -- Create an access-to-C'Class value that -- designates an object of type D, by conversion -- of function result. return CCAccess(NastyAllocator); end Nasty;
A0 : CCAccess := Nasty(1);
Should this hole be plugged? (Yes.)
!recommendation
(See Summary.)
!wording
Modify 4.8(10.1/3):
For any allocator, if the designated type of the type of the allocator is class-wide, then a check is made that the master of the type determined by the subtype_indication, or by the tag of the value of the qualified_expression, includes the elaboration of the type of the allocator. {Similarly, for an allocator that defines the result of a function with an anonymous access-to-tagged-type result, a check is made that the master of the type determined by the subtype_indication, or by the tag of the value of the qualified_expression, includes the master of the object created by the allocator (see 3.10.2).} ...
!discussion
This problem can also happen for an anonymous access to class-wide type. For instance, this same problem can happen if in the example, NastyAllocator has a result type of "access C'Class". The wording attempts to cover both.
!ACATS test
An ACATS C-Test should be created to check examples like the one in the
!question.
!appendix

From: Tucker Taft
Sent: Friday, June 25, 2021  8:28 AM

Subject: Hole in check that global access-to-class-wide doesn't designate 
a nested type extension

An AdaCore engineer (the same one who noticed the confusion with "innermost
master of the call") constructed the following test case which illustrates a
way that you can, by conversion, create an access-to-class-wide value that 
designates an object of a tag is shorter-lived than the access-to-class-wide
type:

   type CCAccess is access all C'Class;

   function Nasty(N : Integer) return CCAccess is
      type D is new C with null record;
 
      function NastyAllocator return access D is
      begin
         return new D'(null record);
      end NastyAllocator;

   begin
      --  Create an access-to-C'Class value that
      --  designates an object of type D, by conversion
      --  of function result.
      return CCAccess(NastyAllocator);
   end Nasty;

   A0 : CCAccess := Nasty(1);

One way to fix this is to make the following modification to 4.8(10.1/3):

  For any allocator, if the designated type of the type of the allocator is 
  class-wide, then a check is made that the master of the type determined by
  the subtype_indication, or by the tag of the value of the
  qualified_expression, includes the elaboration of the type of the allocator.
  {Similarly, for an anonymous allocator that defines the result of a function
  with an access-to-specific-tagged-type result, a check is made that the
  master of the type determined by the subtype_indication, or by the tag of
  the value of the qualified_expression, includes the master of the object
  created by the allocator (see 3.10.2).} ...

****************************************************************

From: Tucker Taft
Sent: Friday, June 25, 2021  8:59 AM

Actually, this same thing can happen if in the example, NastyAllocator has a 
result type of "access C'Class" so the change should be more general,
handling any anonymous access-to-tagged type result:

  For any allocator, if the designated type of the type of the allocator is 
  class-wide, then a check is made that the master of the type determined by
  the subtype_indication, or by the tag of the value of the
  qualified_expression, includes the elaboration of the type of the allocator.
  {Similarly, for an anonymous allocator that defines the result of a function
  with an anonymous access-to-tagged-type result, a check is made that the 
  master of the type determined by the subtype_indication, or by the tag of
  the value of the qualified_expression, includes the master of the object
  created by the allocator (see 3.10.2).} ...

****************************************************************

From: Richard Wai
Sent: Saturday, June 26, 2021  9:57 AM

Iím struggling to see what Iím missing here...

To my eyes, 4.6-24.17/4 (type conversions) makes this situation illegal:

"If the target type is a general access-to-object type, then the operand type 
shall be universal_access or an access-to-object type. Further, if the operand
type is not universal_access:"

...

"The accessibility level of the operand type shall not be statically deeper 
than that of the target type, unless the target type is an anonymous access 
type of a stand-alone object. If the target type is that of such a stand-alone
object, the accessibility level of the operand type shall not be statically
deeper than that of the declaration of the stand-alone object."

The target type is statically deeper than the operand type, and the target
type is not an anonymous access type, so this seems to violate that rule.

I note that GCC-10.3.0 refuses to compile the given example, and apparently
for that reason.

****************************************************************

From: Tucker Taft
Sent: Saturday, June 26, 2021  12:01 PM

...
> The target type is statically deeper than the operand type, and the target 
> type is not an anonymous access type, so this seems to violate that rule.

I presume you meant to say "The operand type is statically deeper than the 
target type, ..."

But in fact, in this odd case, the accessibility level of the operand type is
"passed in" from above as a result of the rules about what is the "master of 
the function call" which, via 3.10.2(10.3/5) inherits the rules from
allocators (3.10.3(14/3)) which says:

... For an anonymous allocator that defines the result of a function with an 
access result, the accessibility level is determined as though the allocator 
were in place of the call of the function; in the special case of a call that
is the operand of a type conversion, the level is that of the target access 
type of the conversion. ...

This is exactly the situation we are in, so the accessibility level of the 
allocator comes from the target type of the conversion (yes, it is effectively
a self-fulfilling prophecy so that the levels will match).

> I note that GCC-10.3.0 refuses to compile the given example, and apparently
> for that reason.

Accessibility associated with anonymous access types is an area where I know 
GNAT has had some issues, so its rejection does not imply this new rule is 
unneeded.

****************************************************************

From: Claire Dross
Sent: Monday, June 28, 2021  3:23 AM

> An AdaCore engineer (the same one who noticed the confusion with "innermost 
> master of the call") constructed the following test case which illustrates 
> a way that you can, by conversion, create an access-to-class-wide value that
> designates an object of a tag is shorter-lived than the access-to-class-wide
> type:

Martin is a researcher in verification of programs who joined AdaCore for a 
postdoctoral contract. His aim is to formalize the soundness of (a part of)
the SPARK language. You might hear from him again, as he is currently very 
seriously trying to understand the Ada rules with respect to accessibility 
rules.

****************************************************************

From: Richard Wai
Sent: Monday, June 28, 2021  10:52 AM

Iíve always felt a little nervous about the special rules for returning access
values from functions..

But GNAT itself has a bunch of concerning traits in this space anyways, so
often the rules donít really ďapplyĒ anyways. Itís fairly common to cause a
segfault if youíre a fan of interface types.

****************************************************************

Questions? Ask the ACAA Technical Agent