Version 1.2 of ai12s/ai12-0278-1.txt

Unformatted version of ai12s/ai12-0278-1.txt version 1.2
Other versions for file ai12s/ai12-0278-1.txt

!standard 3.10.2(10.3/3)          18-07-05 AI12-0278-1/02
!class binding interpretation 18-05-14
!status Amendment 1-2012 18-07-05
!status ARG Approved 11-0-0 18-06-22
!status work item 18-05-14
!status received 18-05-11
!priority Low
!difficulty Easy
!qualifier Omission
!subject Implicit conversions of anonymous return types
!summary
An implicit conversion to a named access type determines the "master of the function call".
!question
Consider:
type Int_Access is access constant Integer;
Glob : Int_Access;
procedure Sink (P : in Int_Access) is begin Glob := P; end Sink;
function Func (Value : aliased in Integer) return access constant Integer is begin return Value'access; -- OK. (This is the motivating case for explicitly -- aliased parameters, it better be legal!) end Func;
declare Local : aliased Integer := 12; begin Sink (Int_Access (Func (Local))); -- (1) Illegal. Sink (Func (Local)); -- (2) Legal? (No.) end; if Glob.all = 12 then -- Oops, derefed object doesn't exist.
We need to determine the master of the function call here.
For (1), we have an explicit conversion to Int_Access. So 3.10.2(13.3/3) applies:
* If the result is of an anonymous access type and is the operand of an explicit conversion, the master is that of the target type of the conversion;
Therefore, the "master of the function call" is that of Int_Access. That makes the parameter Local illegal by 6.4.1(6.4/3).
For (2), however, there is no explicit conversion (just an implicit one, based on 8.6(25.1/3) and the conversion to the type of the parameter). Since there is no explicit conversion, 3.10.2(10.3/3) does not apply, and 3.10.2(10.6/3) appears to apply:
In other cases, the master of the call is that of the innermost master that evaluates the function call.
In such a case, the master is very local and Local is fine. But then Sink can assign the access value into a long-lived object and we have a dangling pointer. Since we can't tolerate that, we need to fix this wording, right? (Yes.)
!recommendation
(See Summary.)
!wording
Modify 3.10.2(10.3/3):
If the result is of an anonymous access type and is {converted to a named access type}[the operand of an explicit conversion], the master is that of the target type of the conversion;
!discussion
Note that the implicit conversion belongs to the operation that uses the call (parameter passing in this case). It happens whenever a type matches some other type during resolution (see 8.6).
---
We used "explicit conversion" in this wording to exclude conversions to anonymous access types (most such types use dynamic levels) - since every anonymous access type is different, any operation involving two anonymous access types involve a conversion. No anonymous access type can be the target of an explicit conversion as one can't actually name the type to write a type conversion. However, we need to include rules for implicit conversions to named access types, lest we have a hole as described in the !question.
!corrigendum 3.10.2(10.3/3)
Replace the paragraph:
by:
!ASIS
No ASIS effect.
!ACATS test
ACATS B-Test B3A2018 has examples using the explicit conversions to test 3.10.2(10.3/3); these could be modified to use implicit conversions instead to test this AI.
!appendix

From: Randy Brukardt
Sent: Friday, May 11, 2018  8:43 PM

...for a trip to the Heart of Darkness. Steve is responsible for this trip, 
but now I've sunk into the tar pit.

Consider (in part) the rules for the "master of the function call":

3.10.2(10.3/3): * If the result is of an anonymous access type and is the 
operand of an explicit conversion, the master is that of the target type of
the conversion;

This "explicit conversion" has been bothering me; shouldn't the same rule 
apply if there is an *implicit* conversion? Perhaps this rules doesn't take
those into account because it predates those conversions *from* anonymous 
access types.

We also have:

3.10.2(10.2/3): If the result is used (in its entirety) to directly initialize
part of an object, the master is that of the object being initialized. 

and
3.10.2(10.6/3): In other cases, the master of the call is that of the 
innermost master that evaluates the function call.

So consider:

    type Int_Access is access constant Integer;

    Glob : Int_Access;

    procedure Sink (P : in Int_Access) is
    begin
        Glob := P;
    end Sink;

    function Func (Value : aliased in Integer) return access constant Integer is
    begin
       return Value'Access; -- OK. (This is the motivating case, it better be legal!)
    end Func;

    declare
        Local : aliased Integer := 12;
    begin
        Sink (Func (Local)); --!!!
    end;
    if Glob.all = 12 then -- Oops, derefed object doesn't exist.

There is an implicit conversion from the anonymous access result type to the 
general access type Int_Access. This is explicitly allowed by 8.6(25.1/3) - a 
new feature in Ada 2012.

If 3.10.2(10.3/3) had applied to the call to Func, then the accessibility of 
the call would have been that of Int_Access, and the parameter Local would 
have been illegal by 6.4.1(6.4/3). (And no dangling pointer could have been
created, obviously.)

However, since the conversion is implicit, one of the other cases applies (not
sure which one of 10.2 or 10.6, but they get the same answer) and the 
accessibility of the call to Func appears to be local to the call to Sink; 
Local is outside of that so the call is legal. But we can then save the 
pointer somewhere long-lived, which can't be intended.

So this looks like a real hole and not just something that bothers me.

The obvious fix is to just drop the word "explicit" from 3.10.2(10.3/3), but
someone will need to see if there is a good reason for limiting that rule to
explicit conversions. Meaning I'll have to put the jungle gear back on to
investigate AI12-0234-1, but before I do I thought I'd ask what the rest of
you think.

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

From: Randy Brukardt
Sent: Friday, May 11, 2018  8:56 PM

One reason might be that all anonymous access types are different, so there 
is always a conversion there, but we probably only want this rule for 
conversions to named access types. Explicit conversions would have been a
nice shorthand for conversion to a named access type (since there cannot be
any explicit conversions to an anonymous access type -- no name, remember?),
except that we forgot (or hadn't decided yet) that there can be implicit 
conversions to named access types as well.

So probably the fix is to replace "explicit conversion" with "conversion to a
named access type", but I'll still need the pith helmet to make sure there
isn't any other issue.

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

From: Tucker Taft
Sent: Saturday, May 12, 2018  8:36 AM

I agree with your conclusion.   Good spelunking, by the way... ;-)

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

From: Randy Brukardt
Sent: Monday, May 14, 2018  8:32 PM

...
> Good spelunking, by the way... ;-)

A pith helmet [The subject of this thread was "Need the Pith Helmet"; that 
came from a private thread with Randy and Steve Baird - Editor.] is the wrong 
equipment for spelunking. Need a hard hat, knee pads, three sources of light, 
and sometimes rope for spelunking. No wonder we're having trouble in 
3.10.2!  ;-)

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

Questions? Ask the ACAA Technical Agent