!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) @drepl @xinbull @dby @xinbull !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! ;-) ****************************************************************