!standard 6.4.1(5.1/4) 20-04-29 AI12-0377-1/01 !standard 6.4.1(5.2/4) !standard 6.4.1(5.3/4) !standard 6.4.1(13.2/4) !standard 6.4.1(13.3/4) !class Amendment 20-04-20 !status work item 20-04-20 !status received 20-04-14 !priority Low !difficulty Medium !subject View conversions and out parameters of types with Default_Value revisited !summary An actual of an out parameter that is a view conversion is illegal if either the target or operand type has Default_Value specified while the other does not. Program_Error is raised if this occurs where one of the types is a generic formal type. !problem Consider this example: procedure View_Conversion_With_Default_Value is type Defaulted_Integer is new Integer with Default_Value => 123; procedure P (X : out Integer) is begin null; -- X happens to be unassigned end P; X : Defaulted_Integer; Y : Defaulted_Integer := 456; begin P (Integer (X)); -- Deinitialize X? P (Integer (Y)); -- Deinitialize Y? end View_Conversion_With_Default_Value; Even though the type of X and Y has specified Default_Value, the value of the actual isn't copied into the formal in this case (it falls under the rule of 6.4.1(15)), leaving the formal parameter uninitialized. Upon return, the value of the formal will be converted to Defaulted_Integer and assigned to the actual object. If the formal wasn't assigned to within the procedure, as in the above example, then the (uninitialized) value that comes back will deinitialize the actual object, which is the sort of thing that shouldn't normally be possible for an object whose type has a specified Default_Value. !proposal (See Summary.) !wording Replace 6.4.1(5.1/3) with: If the mode is out, the actual parameter is a view conversion, and the type of the formal parameter is a scalar type, then either: * neither the target nor operand type have the Default_Value aspect specified; or * there shall exist a type (other than a root numeric type) that is an ancestor of both the target type and the operand type, and both the target and operand types have the Default_Value aspect specified. [Author's note: This removes the access part of this rule, and makes a version apply to all view conversions.] Revert 6.4.1(13.1/4) to its previous version. Delete 6.4.1(13.2-13.4/4), and AARM 6.4.1(13.d/4). Add after 6.4.1(15): * Furthermore, if the type is a scalar type, and the actual parameter is a view conversion, then if neither: * neither the target nor operand type have the Default_Value aspect specified; or * there exists a type (other than a root numeric type) that is an ancestor of both the target type and the operand type, and both the target and operand types have the Default_Value aspect specified then Program_Error is raised; !discussion "Deinitialization" here cannot introduce an invalid value into an object that the compiler assumed to be valid (the conversion back to the actual would still do a subtype check, which would cause Constraint_Error if the value is invalid. Note that the check would be required since one cannot assume anything about out parameters). Even so, it seems dangerous enough that we should take steps to prevent it. The best solution is to make any view conversion used in an out parameter illegal if one type has Default_Value and the other does not. Note that the repeal of 13.1(10/3) by AI12-0376-1 means that having the types be related no longer prevents problems (as a derived type can define a Default_Value when the parent type does not have one), so we would have to do something with this rule in any case. The alternative of passing the default value in problematic cases would make the deinitialization noted in the problem worse (since it would clobber the current value of the object unconditionally, even if it would be in range), so that is not a viable solution to this problem. !ASIS No ASIS effect. !ACATS test An ACATS B-Test is needed to check that the new rules are enforced, rather than the previous rules. !appendix From: Gary Dismukes Sent: Tuesday, April 14, 2020 5:43 PM Recently, while fixing a GNAT problem related to passing view conversions to out-mode parameters when Default_Value is involved (related to the rules added in AI12-0074), it occurred to me that there's a similar situation that can arise when the formal type doesn't have aspect Default_Value, but the type of the operand of the view conversion does have the aspect. (AI12-0074 addressed the case of formal types that specific Default_Value, requiring the type of an operand of a view conversion actual to also specify Default_Value, and this is sort of the reverse of that.) Consider this example, which is a minor variation of the one in the AI: procedure View_Conversion_With_Default_Value is type Defaulted_Integer is new Integer with Default_Value => 123; procedure P (X : out Integer) is begin null; -- X happens to be unassigned end P; X : Defaulted_Integer; Y : Defaulted_Integer := 456; begin P (Integer (X)); -- Deinitialize X? P (Integer (Y)); -- Deinitialize Y? end View_Conversion_With_Default_Value; Even though the type of X and Y has specified Default_Value, the value of the actual isn't copied into the formal in this case (it falls under the rule of 6.4.1(15)), leaving the formal parameter uninitialized. Upon return, the value of the formal will be converted to Defaulted_Integer and assigned to the actual object. If the formal wasn't assigned to within the procedure, as in the above example, then the (uninitialized) value that comes back will deinitialize the actual object, which is the sort of thing that shouldn't normally be possible for an object whose type has a specified Default_Value. You could argue that you shouldn't have a formal of mode out that isn't assigned to, but that's kind of beside the point, because the normal guarantee of Default_Value, that variables of the type always have a good value, is violated in this case, so we clearly have a safety hazard. To avoid this, the rules either need to require the value of the actual to be assigned to the formal going in, or such a conversion needs to be rejected. I was initially leaning towards the former, but Tuck has convinced me that this should be illegal. Basically we don't want to impose the penalty of preventing an optimization like transforming a procedure with a single elementary out formal into a function returning the parameter, just to protect against what is going to be the rare case of passing a view conversion of an operand with Default_Value. So it seems that we need to augment the rules of 6.4.1(5.1-5.3), which require the type of the operand of a view conversion to have Default_Value when the formal's type has Default_Value. We need to also disallow the case where a view conversion operand's type has Default_Value but the formal's type doesn't. I believe we'll also need to add something along the lines of the rules in 6.4.1(13.1-13.4) that require Program_Error be raised, to address call cases within generic bodies when formal types are involved (those rules were also added by AI12-0074). **************************************************************** From: Tucker Taft Sent: Tuesday, April 14, 2020 7:49 PM We have discussed this internally at AdaCore, and concluded that we should make it illegal to pass a scalar type with Default_Value in a view conversion to an OUT formal parameter without a Default_Value. Requiring "copy in" is not practical given the way that OUT parameters of a scalar type are sometimes implemented (such as transforming the procedure to a function and returning the OUT parameter as a function result). **************************************************************** From: Randy Brukardt Sent: Tuesday, April 21, 2020 7:57 PM > Recently, while fixing a GNAT problem related to passing view > conversions to out-mode parameters when Default_Value is > involved (related to the rules added in AI12-0074), it > occurred to me that there's a similar situation that can > arise when the formal type doesn't have aspect Default_Value, > but the type of the operand of the view conversion does have > the aspect. (AI12-0074 addressed the case of formal types > that specific Default_Value, requiring the type of an operand > of a view conversion actual to also specify Default_Value, > and this is sort of the reverse of that.) I'm not throughly convinced that this problem (in any form) is worth worrying about, since it can't cause an invalid value to be introduced to the program (at least in a correct implementation). If the implementation is assuming that the actual object is valid, then a constraint check is necessary at the back assignment and that would prevent any invalid values from being stored. The value would indeed be junk, but that's what was written (and it happens for all scalar out parameters). Anyway, assuming that we do want to keep this illegal in any case, we need to cover *this* case as well. Attached is an attempt at doing that, and also handling the access problem (with a solution close to what GNAT is currently doing). I suspect that the AI and especially the wording will need some wordsmithing. ****************************************************************