CVS difference for 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