CVS difference for ai12s/ai12-0377-1.txt

Differences between 1.3 and version 1.4
Log of other versions for file ai12s/ai12-0377-1.txt

--- ai12s/ai12-0377-1.txt	2020/04/28 03:47:33	1.3
+++ ai12s/ai12-0377-1.txt	2020/05/02 03:43:14	1.4
@@ -1,15 +1,14 @@
-!standard 6.4.1(5.1/4)                                  20-04-20  AI12-0377-1/01
+!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/3)
 !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-03-26
+!status received 20-04-14
 !priority Low
 !difficulty Medium
-!subject  View conversions and out parameters passed by copy revisited
+!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 
@@ -17,14 +16,9 @@
 not. Program_Error is raised if this occurs where one of the types is a 
 generic formal type.
 
-An actual of an out parameter that is a view conversion of an access type
-is not illegal if the types are not related, rather null is passed if the
-access value fails a membership check on the subtype of the parameter
-(ignoring any exclusion or predicate).
-
 !problem
 
-(1) Consider this example:
+Consider this example:
 
    procedure View_Conversion_With_Default_Value is
 
@@ -55,11 +49,6 @@
 object, which is the sort of thing that shouldn't normally be possible for an
 object whose type has a specified Default_Value.
 
-(2) The legality rule that prevents view conversions of unrelated access types
-for out parameters is a compatibility problem in practice. When we implemented
-this in GNAT, a significant number of incompatibilities in our customer 
-regression test suite failed to compile.
-
 !proposal
 
 (See Summary.)
@@ -78,29 +67,6 @@
 [Author's note: This removes the access part of this rule, and makes a 
 version apply to all view conversions.]
 
-Modify 6.4.1(13/3):
-
-[Author's Note: Broken into two bullets. I couldn't figure out how to factor
-out the "without checking" part of the rule; it would be best to do that to
-decrease the noise.]
-
-For an access type,
-
-{* if a membership test of the value of the actual against
-the subtype of the parameter, ignoring the result of any predicate or the 
-exclusion of the null value, yields True, then} the formal parameter is 
-initialized from the value of the actual, without checking that the value 
-satisfies [any constraint, ]any predicate[,] or any exclusion of the null value; 
-
-{* otherwise, the the formal parameter is initialized to the
-null value of the formal type, without checking that the value 
-satisfies any predicate or any exclusion of the null value.}
-
-AARM Implementation Note: This rule means that any constraint checks, tag 
-checks, and accessibility checks can be assumed to pass for an out parameter,
-but null exclusions and predicates cannot be assumed unless the compiler can
-prove that the object has been previously written within the subprogram.
-
 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).
@@ -117,8 +83,8 @@
 
 !discussion
 
-For [1], note that "deinitialization" here cannot introduce an invalid value 
-into an object that the compiler assumed to be valid (the conversion back to 
+"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 
@@ -136,117 +102,6 @@
 current value of the object unconditionally, even if it would be in range),
 so that is not a viable solution to this problem.
 
-For [2], it's fairly clear that we cannot have the original Legality Rule, as
-it seems too incompatible. However, this problem occurs not only for access
-types with different sizes (as outlined in the original AI12-0074-1), but also
-for any case where the generated code may need to know details about an out
-parameter. Three such cases were identified in the e-mail attached to 
-AI12-0074-1:
-
-     [A] Cases involving discriminant checks;
-     [B] Cases involving tag checks;
-     [C] Cases involving accessibility checks.
-
-These cases can be seen in the test program given at the start of the !appendix
-for this AI (more on this test program below).
-
-An implementation could assume that all out parameters are unconstrained (and 
-thus making the discriminant checks on every use), thus defanging problemg [A].
-This would not be problematic. However, the tag and accessibility checks are 
-not normally done as usage sites, so assuming implementations will do the
-right thing would impose a substantial implementation burden for a very
-unusual case (but one that is not quite as pathological as we expected in
-AI12-0074-1).
-
-We created a test program to see what existing compilers do in these cases.
-The test program is reproduced at the start of the !appendix. The test program
-includes a few preliminary cases to check what an implementation does in
-cases not involved with the cases in question, then it tries each of the three
-problematic examples in turn.
-
-Running the test program on a recent version of GNAT (from February 2020) 
-shows that it side-steps this problem by passing null to any out parameter 
-when the actual is an explicit view conversion. The implicit view conversion 
-of derivation works as expected, however, so we have a case where one cannot 
-write the same thing as the compiler does automatically.
-
-Running the test program on a recent version of ObjectAda (thanks to PTC for
-providing these results): The discriminant and accessibility cases do not 
-compile (ObjectAda rejects the conversions suggesting an Ada 2005 
-implementation of those). ObjectAda fully supports the derived type cases,
-including using explicit conversions. The tagged type case causes no errors
-nor obvious overwriting of memory (but it is not clear what actually was
-written).
-
-Running the test program on a recent version of ApexAda (thanks to PTC for
-providing these results): The accessibility cases do not compile (ApexAda
-rejects the conversion with a static accessibility check). ObjectAda fully 
-supports the derived type cases, including using explicit conversions. The 
-discriminant case shows that ApexAda does not assume the constraints of an
-out parameter, so a check was made and Constraint_Error raised. The tagged 
-type case causes no errors nor obvious overwriting of memory (but it is not 
-clear what actually was written).
-
-Running the test program on a recent version of Janus/Ada shows that it fully
-supports the derived type cases; it assumes that out parameters do not enforce
-their constraints (so that they are effectively unconstrained); other memory
-is overwritten by the tagged case (execution is erroneous); and the 
-accessibility case does not compile (Janus/Ada does not yet support dynamic
-accessibility for stand-alone objects of anonymous access types).
-
----
-
-These results suggest that having problematic cases use the GNAT rule of
-passing null would not be significantly incompatible in practice. We would
-only want to use such a rule in cases that are actually problems, in order
-that derivation works as expected (as noted in the preliminary parts of
-the test program), and so that explicit calls that are exactly like calls on
-inherited subprograms work the same way as the inherited call. Note that
-GNAT is the only compiler that passes null currently, other compilers 
-implement the language as defined more closely.
-
-Note that an out parameter can always be null, even if the parameter is 
-declared with a null exclusion. Null exclusions are not checked when the
-parameter is passed in, and null is passed when the actual is not
-convertable. An implementation should not assume that null exclusions of an
-out parameter are enforced before the out parameter is written within the
-subprogram. 
-
-We could have required null to be passed for all out parameters of access 
-types. That may have been a more sensible rule for a new language, but it
-would mean that changing an out parameter of a record type to an 
-access-to-record type would also require changing the mode to "in out"
-if any discriminants or bounds need to be read. Presumably, that is why
-Ada initially made the choice it did. In any case, the runtime incompatiblity
-creating by generally making such a change would be intolerable, so it is
-much too late to contemplate that.
-
-The only other alternative to requiring null to be passed would be to declare 
-that the value of an out parameter whose actual is a view conversion and whose 
-value does not pass a membership test for the subtype of the parameter is 
-abnormal. In that case, reading the value within the subprogram makes the 
-program erroneous (while assigning it first is fine). This would work but it
-introduces erroneous execution where none is really needed (the passing null
-solution involves no erroneous execution).
-
----
-
-Note that we don't explicitly talk about converting between access types with
-different representations. We're expecting that an implementation with such
-representations will include them in conversion and membership checking in an
-appropriate manner. For instance, if one assumes that converting a bit pointer
-to a byte pointer raises an exception if the bit address is not an even byte, 
-then so long as that is reflected in a membership test, all is well.
-
-It's true that there doesn't seem to be any justification within the language
-to raise an exception in such a case, but it seems nasty to simply destroy an
-access value if the target type cannot properly represent the address. (Note
-that a similar thing can happen on a segmented machine, such as the original
-8086.) One assumes that Ada implementations care enough about correctness to
-avoid user-beware cases. If they don't, it's not the language's job to try to
-fix them.
-[Author's note: We may want to add an AARM note somewhere in 4.6 to note this 
-possibility, and possibly in 4.5.2 as well.]
 
 !ASIS
 
@@ -254,344 +109,11 @@
 
 !ACATS test
 
-ACATS B- and C-Tests are needed to check that the new rules are enforced,
-rather than the previous rules. The test program given below can be the
-basis of an ACATS C-Test.
+An ACATS B-Test is needed to check that the new rules are enforced,
+rather than the previous rules.
 
 !appendix
 
-From: Randy Brukardt
-Sent: Never [Done April 20, 2020]
-
-[Following is the test program for AI12-0377-1.]
-
-with Ada.Text_IO, Ada.Exceptions;
-procedure TestAI74 is
-begin
-
-    -- Note: The three "problems" were identified during the work on 
-    -- AI12-0074-1. We're testing what they do on existing implementations
-    -- during a revisit of these rules. Note: All of these "problems"
-    -- were made illegal by AI12-0074-1, so a correct Ada 2012 implementation
-    -- would reject this program. If so, please try each case individually
-    -- to provide us the maximum information about runtime behavior.
-    -- Note that many of these cases are allowed by Ada 95 and Ada 2005.
-    
-    Ada.Text_IO.Put_Line ("Check some nasty cases related to AI12-0377-1");
-  
-  
-    -- Behavior of view conversions and derivation
-    -- Note: This example is fully legal, no Ada 2012 compiler (or Ada 95
-    -- compiler, for that matter) should reject this.
-    declare
-       package Nest is
-           type T (D : Boolean := False) is -- no partial view
-              record
-                 case D is
-                    when False => Bar : Character;
-                    when True  => Foo : Integer;
-                 end case;
-              end record;
-
-           type Unconstrained_Ref is access all T;
-
-           procedure Q (X : out Unconstrained_Ref);
-               -- A primitive of Unconstrained_Ref
-               
-           type Derived_Ref is new Unconstrained_Ref;
-           
-           -- Inherits Q.
-
-       end Nest;
-        
-       package body Nest is
-           procedure Q (X : out Unconstrained_Ref) is
-           begin
-              if X.D then
-                  X.Foo := 456;
-              else
-                  X.Bar := 'B';
-              end if;
-           end Q;
-       end Nest;
- 
-       X : aliased Nest.T := (D => False, Bar => 'R');
-       X_Ref : Nest.Unconstrained_Ref := X'Access;
- 
-       Der_X_Ref : Nest.Derived_Ref := X'Access;     
-       
-    begin
-        -- Direct call to Q:
-        begin
-          Nest.Q (X_Ref);
-          if X.Bar /= 'B' then
-             Ada.Text_IO.Put_Line ("** Component not changed");
-          else
-             Ada.Text_IO.Put_Line ("-- Expected result, no conversion");
-          end if;
-        exception
-          when Err:others =>
-             Ada.Text_IO.Put_Line ("** Failed: Exception raised (no conversion) - " & 
-                                        Ada.Exceptions.Exception_Information (Err));
-        end;
-        -- View conversion to parent type:
-        begin
-          X.Bar := 'R';
-          Nest.Q (Nest.Unconstrained_Ref (Der_X_Ref));
-          if X.Bar /= 'B' then
-             Ada.Text_IO.Put_Line ("** Component not changed");
-          else
-             Ada.Text_IO.Put_Line ("-- Expected result, explicit parent conversion");
-          end if;
-       exception
-          when Err:others =>
-             Ada.Text_IO.Put_Line ("** Failed: Exception raised (explicit parent conversion) - " & 
-                                        Ada.Exceptions.Exception_Information (Err));
-       end;
-       -- Call to inherited routine (implicit view conversion to parent type):
-       begin
-          X.Bar := 'R';
-          Nest.Q (Der_X_Ref);
-          if X.Bar /= 'B' then
-             Ada.Text_IO.Put_Line ("** Component not changed");
-          else
-             Ada.Text_IO.Put_Line ("-- Expected result, inherited routine");
-          end if;
-       exception
-          when Err:others =>
-             Ada.Text_IO.Put_Line ("** Failed: Exception raised (inherited routine) - " & 
-                                        Ada.Exceptions.Exception_Information (Err));
-       end;
-    end;
-        
-    -- A discriminant problem
-    declare
-       type T (D : Boolean := False) is -- no partial view
-          record
-             case D is
-                when False => Bar : Character;
-                when True  => Foo : Integer;
-             end case;
-          end record;
-
-       type Unconstrained_Ref is access all T;
-       type Constrained_Ref is access all T (True);
-
-       X : aliased T := (D => False, Bar => 'R');
-       X_Ref : Unconstrained_Ref := X'Access;
-
-       procedure P (X : out Constrained_Ref) is
-       begin
-          X.Foo := 123;
-            --  We don't want to require a discriminant
-            --  check here.
-       end P;
- 
-    begin
-       P (Constrained_Ref (X_Ref));
-       if X.D /= False then
-           Ada.Text_IO.Put_Line ("** Discriminant changed");
-       else
-           Ada.Text_IO.Put_Line ("?? Possible erroneous execution");
-           Ada.Text_IO.Put_Line ("?? X.Bar'Pos = " & Natural'Image (Character'Pos (X.Bar)));
-       end if;
-    exception
-       when Err2:Constraint_Error =>
-          Ada.Text_IO.Put_Line ("-- Discriminant check made anyway - " &
-                                    Ada.Exceptions.Exception_Information (Err2));
-       when Err:others =>
-          Ada.Text_IO.Put_Line ("** Exception raised (disc) - " & Ada.Exceptions.Exception_Information (Err));
-    end;
-
-    -- A tag problem
-    declare
-       type Root is tagged null record;
-       type Ext is new Root with record F : Integer; end record;
-
-       type Root_Ref is access all Root'Class;
-       type Ext_Ref is access all Ext;
-
-       procedure P (X : out Ext_Ref) is
-       begin
-          X.F := 123;
-            -- No tag check is performed here and
-            -- we don't want to add one.
-          X := null;
-       end P;
-
-       R : aliased Root;
-       O : Integer := 12;
-       Ptr : Root_Ref := R'Access;
-    begin
-       P (Ext_Ref (Ptr));
-       Ada.Text_IO.Put_Line ("?? Possible erroneous execution");
-       if R not in Root then
-           Ada.Text_IO.Put_Line ("** Object tag changed");
-       end if;
-       if O /= 12 then
-           Ada.Text_IO.Put_Line ("** Following object clobbered to " & Integer'Image(O));
-       end if;
-    exception
-       when Err:others =>
-          Ada.Text_IO.Put_Line ("-- Exception raised (tag) - " & Ada.Exceptions.Exception_Information (Err));
-    end;
-
-    -- An accessibility problem
-    declare
-       type Int_Ref is access all Integer;
-       Dangler : Int_Ref;
-       procedure P (X : out Int_Ref) is
-       begin
-          Dangler := X;
-            -- No accessibility checks are performed here.
-            -- We rely here on the invariant that
-            -- a value of type Int_Ref cannot designate
-            -- an object with a shorter lifetime than Int_Ref.
-          X := null;
-       end P;
-
-       procedure Q is
-          Local_Int : aliased Integer;
-          Standalone : access Integer := Local_Int'Access;
-       begin
-          P (Int_Ref (Standalone));
-          null;
-       end Q;
-    begin
-       Q;
-       Dangler.all := 123; -- Assigns a non-existent object, can't check this.
-       Ada.Text_IO.Put_Line ("?? Likely erroneous execution");
-    exception
-       when Err:others =>
-          Ada.Text_IO.Put_Line ("-- Exception raised (acc) - " & Ada.Exceptions.Exception_Information (Err));
-    end;
-    
-    Ada.Text_IO.Put_Line ("Test finished");
-
-end TestAI74;
-
-****************************************************************
-
-From: Randy Brukardt
-Sent: Never [Done April 20, 2020]
-
-Here's the results of the above test program when run on GNAT 21.0w-200219:
-
-Check some nasty cases related to AI12-0377-1
--- ersion
-** Failed: Exception raised (explicit parent conversion) - raised CONSTRAINT_ERROR : testai74.adb:42 access check failed
-
--- ed routine
--- anyway - raised CONSTRAINT_ERROR : testai74.adb:117 access check failed
-
---  raised CONSTRAINT_ERROR : testai74.adb:148 access check failed
-
---  raised CONSTRAINT_ERROR : testai74.adb:194 access check failed
-
-Test finished
-
-****************************************************************
-
-From: Randy Brukardt
-Sent: Never [Done April 20, 2020]
-
-Here's the results of the above test program when run on Janus/Ada 3.2.2dev (4/20/20):
-
-[Note: Janus/Ada needed the call in the third case commented out, since it 
-does not support dynamic accessibility for stand-alone objects of an anonymous
-access type. Thus the last case is uninteresting as it didn't set Dangler.]
-
-Check some nasty cases related to AI12-0377-1
--- ersion
--- t parent conversion
--- ed routine
--- anyway - CONSTRAINT_ERROR
-   Variant record field not available
-On Line Number 117 In TESTAI74.LOOP.P
-Called from line number 123 In TESTAI74
-
-?? Possible erroneous execution
-** Following object clobbered to  123
---  CONSTRAINT_ERROR
-   Attempt to reference thru NULL/Uninitialized pointer
-On Line Number 194 In TESTAI74
-
-Test finished
-
-****************************************************************
-
-From: Randy Brukardt
-Sent: Never [Done April 21, 2020]
-
-Here's the results of the above test program when run on ObjectAda 10.1 
-(4/21/20) [thanks to PTC for these results]
-
-[Note: ObjectAda needed the first and third error cases commented out, as it
-rejected both of the conversions in those two cases.]
-
-Check some nasty cases related to AI12-0377-1
--- ersion
--- t parent conversion
--- ed routine
-?? Possible erroneous execution
-Test finished
-
-****************************************************************
-
-From: Randy Brukardt
-Sent: Never [Done April 21, 2020]
-
-Here's the results of the above test program when run on ApexAda 5.2 
-(4/21/20) [thanks to PTC for these results]
-
-[Note: ApexAda needed the third error cases commented out, as it
-rejected the conversion with a static accessibility failure.]
-
-Check some nasty cases related to AI12-0377-1
--- ersion
--- t parent conversion
--- ed routine
--- anyway - CONSTRAINT_ERROR raised at 16#000000000040439B#, Exception Message: 
-?? Possible erroneous execution
-
-****************************************************************
-
-From: Tucker Taft
-Sent: Thursday, March 26, 2020  9:29 AM
-
-AdaCore recently implemented this Corrigendum AI, and bumped into a 
-significant number of incompatibilities in their customer regression test 
-suite in the access-type-related part, which disallows view conversions 
-between unrelated access types on an actual parameter if the formal is mode
-"out."  The AI argued that such situations should be rare, but apparently it
-is more common than we anticipated.
-
-I would suggest we remove the access-type-related part from this AI, put it 
-in a separate AI, and consider voting it "no action," or come up with a more
-compatible approach (e.g. disallow only if the Sizes for the access types 
-differ).
-
-****************************************************************
-
-From: Randy Brukardt
-Sent: Tuesday, April 21, 2020  6:51 PM
-
-It turns out that GNAT "solves" this problem by always passing null for an 
-explicit view conversion of an out parameter. It completely ignores what the 
-language says to do in such a case.
-
-Probably some solution based on that would be best, although we need to take 
-care not to break existing code that takes advantage of the language as 
-written (since that goes back to Ada 95). Unless, of course, none exists; I've
-asked implementers about this question in order to see if we get any feedback.
-
-AI12-0377-1 will cover this issue and the other one that Gary posted (they're 
-both related to AI12-0074-1, which is a Corrigendum AI, and which will need 
-to be revisited in any case because of the intent to repeal 13.1(10). I'll 
-post this AI later today.
-
-****************************************************************
-
 From: Gary Dismukes
 Sent: Tuesday, April 14, 2020  5:43 PM
 
@@ -701,23 +223,5 @@
 doing).
 
 I suspect that the AI and especially the wording will need some wordsmithing.
-
-****************************************************************
-
-From: Randy Brukardt
-Sent: Wednesday, April 22, 2020  1:44 PM
-
-FYI, I asked PTC (and received almost immediately) about their compilers 
-behavior on the test program. Both of their compilers behaved similarly to 
-the results I reported for Janus/Ada (including not supporting dynamic 
-accessibility on SAOAATs), with the exception of ObjectAda rejecting the 
-conversion in the first test case. Details are found in the posted AI (not the 
-one attached previously, I got an answer from PTC after I sent the previous 
-e-mail).
-
-I conclude that taking GNAT's behavior exactly would have a serious risk of 
-being run-time incompatible with existing code (a risk we shouldn't take). A 
-more limited form, however, seems to be the right solution (surely we don't 
-want the erroneous execution that all of the non-GNAT compilers have).
 
 ****************************************************************

Questions? Ask the ACAA Technical Agent