CVS difference for ai12s/ai12-0378-1.txt
--- ai12s/ai12-0378-1.txt 2020/05/16 05:45:04 1.1
+++ ai12s/ai12-0378-1.txt 2020/06/08 00:10:27 1.2
@@ -1,4 +1,4 @@
-!standard 6.4.1(13/3) 20-04-29 AI12-0378-1/01
+!standard 6.4.1(13/3) 20-06-07 AI12-0378-1/02
!class Amendment 20-04-29
!status work item 20-04-29
!status received 20-03-26
@@ -9,15 +9,15 @@
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
+access value would fail a membership check on the subtype of the parameter
(ignoring any exclusion or predicate).
!problem
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.
+this in GNAT, a significant number of tests in our customer regression test
+suite failed to compile.
!proposal
@@ -27,34 +27,38 @@
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.
+[Author's Note: Broken into two bullets.]
+ * For an access type,[ 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;]
+
+ {* if the value is nonnull, satisfies any constraints of the formal,
+ has an accessibility level no deeper than that of the type of the
+ formal, and, if the designated type is tagged, the tag of the
+ designated object identifies a type that is covered by the type of
+ the formal, the formal parameter is initialized from the value of
+ the actual, without checking whether the value satisfies any
+ predicate;
+
+ * 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.
+
+
!discussion
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
+parameter. Three such cases were identified in the e-mail attached to
AI12-0074-1:
[A] Cases involving discriminant checks;
@@ -64,9 +68,9 @@
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
+An implementation could assume that all out parameters are unconstrained (and
thus making the discriminant checks on every use), thus defanging problem [A].
-This would not be problematic. However, the tag and accessibility checks are
+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
@@ -78,15 +82,15 @@
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
+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 95
+providing these results): The discriminant and accessibility cases do not
+compile (ObjectAda rejects the conversions suggesting an Ada 95
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 successfully
@@ -94,17 +98,17 @@
Running the test program on a recent version of ApexAda (thanks again to PTC
for providing these results): The accessibility cases do not compile (ApexAda
-rejects the conversion with a static accessibility check). ApexAda fully
-supports the derived type cases, including using explicit conversions. The
+rejects the conversion with a static accessibility check). ApexAda 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
+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 successfully writing the nonexistent component actually did).
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 and raises
-Constraint_Error when incorrect); other memory is overwritten by the tagged
+their constraints (so that they are effectively unconstrained and raises
+Constraint_Error when incorrect); 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).
@@ -117,29 +121,29 @@
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
+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
+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.
+subprogram.
-We could have required null to be passed for all out parameters of access
+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
+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
+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).
@@ -150,7 +154,7 @@
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,
+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
@@ -160,7 +164,7 @@
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
+[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
@@ -184,17 +188,17 @@
procedure TestAI74 is
begin
- -- Note: The three "problems" were identified during the work on
+ -- 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-0378-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.
@@ -212,13 +216,13 @@
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
@@ -229,12 +233,12 @@
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;
-
+
+ Der_X_Ref : Nest.Derived_Ref := X'Access;
+
begin
-- Direct call to Q:
begin
@@ -246,7 +250,7 @@
end if;
exception
when Err:others =>
- Ada.Text_IO.Put_Line ("** Failed: Exception raised (no conversion) - " &
+ Ada.Text_IO.Put_Line ("** Failed: Exception raised (no conversion) - " &
Ada.Exceptions.Exception_Information (Err));
end;
-- View conversion to parent type:
@@ -260,7 +264,7 @@
end if;
exception
when Err:others =>
- Ada.Text_IO.Put_Line ("** Failed: Exception raised (explicit parent conversion) - " &
+ 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):
@@ -274,11 +278,11 @@
end if;
exception
when Err:others =>
- Ada.Text_IO.Put_Line ("** Failed: Exception raised (inherited routine) - " &
+ 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
@@ -301,7 +305,7 @@
-- We don't want to require a discriminant
-- check here.
end P;
-
+
begin
P (Constrained_Ref (X_Ref));
if X.D /= False then
@@ -380,7 +384,7 @@
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;
@@ -412,7 +416,7 @@
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
+[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.]
@@ -438,7 +442,7 @@
From: Randy Brukardt
Sent: Never [Done April 21, 2020]
-Here's the results of the above test program when run on ObjectAda 10.1
+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
@@ -456,7 +460,7 @@
From: Randy Brukardt
Sent: Never [Done April 21, 2020]
-Here's the results of the above test program when run on ApexAda 5.2
+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
@@ -466,7 +470,7 @@
-- Expected result, no conversion
-- Expected result, explicit parent conversion
-- Expected result, inherited routine
--- anyway - CONSTRAINT_ERROR raised at 16#000000000040439B#, Exception Message:
+-- Discriminant check made anyway - CONSTRAINT_ERROR raised at 16#000000000040439B#, Exception Message:
?? Possible erroneous execution
Test finished
@@ -475,16 +479,16 @@
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
+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
+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
+compatible approach (e.g. disallow only if the Sizes for the access types
differ).
****************************************************************
@@ -492,18 +496,18 @@
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
+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
+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
+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.
****************************************************************
@@ -511,17 +515,17 @@
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
+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
+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).
****************************************************************
@@ -535,29 +539,29 @@
Wording suggestion:
-{* if the value is nonnull and belongs to the subtype of the parameter, then}
-the formal parameter is initialized from the value of the actual, without
+{* if the value is nonnull and belongs to the subtype of the parameter, then}
+the formal parameter is initialized from the value of the actual, without
checking whether the value satisfies any predicate
-{* otherwise, the the formal parameter is initialized to the null value of the
-type of the formal, without checking that the value satisfies any predicate or
-any exclusion of the null value.}
+{* otherwise, the the formal parameter is initialized to the null value of the
+type of the formal, without checking that the value satisfies any predicate or
+any exclusion of the null value.}
****************************************************************
From: Randy Brukardt
Sent: Wednesday, April 29, 2020 3:21 PM
-"belongs" only describes constraints, and really only makes sense for related
-types. When you are converting *un*related types, there is a bunch of dynamic
-checks that are in addition to the constraint checks. For access types, these
-are 4.6(24.11-24.17) - seven paragraphs. These are repeated (ugh!) for
-memberships in 4.5.2(30.3/4), slightly differently since the result is
-True/False rather than raising an exception. I though it was best to piggyback
-on that paragraph rather than writing something new that would be forever
+"belongs" only describes constraints, and really only makes sense for related
+types. When you are converting *un*related types, there is a bunch of dynamic
+checks that are in addition to the constraint checks. For access types, these
+are 4.6(24.11-24.17) - seven paragraphs. These are repeated (ugh!) for
+memberships in 4.5.2(30.3/4), slightly differently since the result is
+True/False rather than raising an exception. I though it was best to piggyback
+on that paragraph rather than writing something new that would be forever
wrong.
-I had hoped there was a term like "convertible" (but that term is static only)
+I had hoped there was a term like "convertible" (but that term is static only)
to cover this, but it doesn't exist. We could try to add one but I thought that
was overkill for this particular fix.
@@ -568,28 +572,28 @@
From: Tucker Taft
Sent: Wednesday, April 29, 2020 4:02 PM
->"belongs" only describes constraints, and really only makes sense for related
->types. When you are converting *un*related types, there is a bunch of dynamic
->checks that are in addition to the constraint checks. For access types, these
+>"belongs" only describes constraints, and really only makes sense for related
+>types. When you are converting *un*related types, there is a bunch of dynamic
+>checks that are in addition to the constraint checks. For access types, these
>are 4.6(24.11-24.17) - seven paragraphs.
-In my RM, those are all legality rules, so would not need to be repeated. The
-dynamic semantics are in (48-50). And I think some of them could be
+In my RM, those are all legality rules, so would not need to be repeated. The
+dynamic semantics are in (48-50). And I think some of them could be
simplified in this situation.
->These are repeated (ugh!) for memberships in 4.5.2(30.3/4), slightly
->differently since the result is True/False rather than raising an exception.
->I though it was best to piggyback on that paragraph rather than writing
+>These are repeated (ugh!) for memberships in 4.5.2(30.3/4), slightly
+>differently since the result is True/False rather than raising an exception.
+>I though it was best to piggyback on that paragraph rather than writing
>something new that would be forever wrong.
-I'd like to at least try to come up with some wording that is simpler. Good
-point about "belongs" but it still does some of what we want. It also seems
+I'd like to at least try to come up with some wording that is simpler. Good
+point about "belongs" but it still does some of what we want. It also seems
more natural to piggyback on wording having to do with conversion, rather than
-membership test. And there is already wording there for view conversion, so
+membership test. And there is already wording there for view conversion, so
perhaps we should put it all in 4.6, and keep 6.4.1 very simple.
->I had hoped there was a term like "convertible" (but that term is static
->only) to cover this, but it doesn't exist. We could try to add one but I
+>I had hoped there was a term like "convertible" (but that term is static
+>only) to cover this, but it doesn't exist. We could try to add one but I
>thought that was overkill for this particular fix.
Moving most of it to 4.6 from 6.4.1 might help.
@@ -604,10 +608,10 @@
Sent: Wednesday, April 29, 2020 4:57 PM
...
-> I had hoped there was a term like "convertible" (but that term is
+> I had hoped there was a term like "convertible" (but that term is
> static only)
-So what? Surely I can use a term of static semantics in describing a dynamic
+So what? Surely I can use a term of static semantics in describing a dynamic
constraint.
(Seems to me that the term has a perfect fit in context: "convertible"
@@ -619,43 +623,43 @@
Sent: Wednesday, April 29, 2020 5:18 PM
...
->> I had hoped there was a term like "convertible" (but that term is
+>> I had hoped there was a term like "convertible" (but that term is
>> static only)
->
-> So what? Surely I can use a term of static semantics in describing a
+>
+> So what? Surely I can use a term of static semantics in describing a
> dynamic constraint.
-Again, this is about dynamic semantics, so we should be able to presume that
-legality rules have already been enforced. I think some of Randy's comments
+Again, this is about dynamic semantics, so we should be able to presume that
+legality rules have already been enforced. I think some of Randy's comments
were about legality rules or static semantics, so don't really apply either.
-
+
****************************************************************
From: Randy Brukardt
Sent: Wednesday, April 29, 2020 6:45 PM
->>"belongs" only describes constraints, and really only makes sense for
->>related types. When you are converting *un*related types, there is a
+>>"belongs" only describes constraints, and really only makes sense for
+>>related types. When you are converting *un*related types, there is a
>>bunch of dynamic checks that are in addition to the constraint checks.
>>For access types, these are 4.6(24.11-24.17) - seven paragraphs.
->In my RM, those are all legality rules, so would not need to be repeated.
->The dynamic semantics are in (48-50). And I think some of them could be
+>In my RM, those are all legality rules, so would not need to be repeated.
+>The dynamic semantics are in (48-50). And I think some of them could be
>simplified in this situation.
-Sorry, I'm only talking about the Dynamic Semantics rules, whereever they
-are. :-) There are tag and accessibility checks on top of the constraint,
+Sorry, I'm only talking about the Dynamic Semantics rules, whereever they
+are. :-) There are tag and accessibility checks on top of the constraint,
null exclusion, and predicate checks, Here, there's no execution issue with
-predicates and it's better to skip them. The null exclusion doesn't change
-anything -- those fail if the value is null, but replacing null by null
-doesn't change anything so forget that. Constraints can go either way -- we
-already have to treat out parameters are unconstrained for other types (in
-particular, integer types) so doing so as well for access types (for which
-constraints are already strange) isn't a huge issue. (No compiler crashed
-that allowed that, both Janus/Ada and ApexAda raised Constraint_Error.
-ObjectAda incorrectly banned the conversion, and GNAT of course passed null
-for any such conversion, even one that has no semantic effect.) But once we
+predicates and it's better to skip them. The null exclusion doesn't change
+anything -- those fail if the value is null, but replacing null by null
+doesn't change anything so forget that. Constraints can go either way -- we
+already have to treat out parameters are unconstrained for other types (in
+particular, integer types) so doing so as well for access types (for which
+constraints are already strange) isn't a huge issue. (No compiler crashed
+that allowed that, both Janus/Ada and ApexAda raised Constraint_Error.
+ObjectAda incorrectly banned the conversion, and GNAT of course passed null
+for any such conversion, even one that has no semantic effect.) But once we
start making some sort of check, it's probably easier to include constraints
-in it -- those are rare anyway.
+in it -- those are rare anyway.
****************************************************************
Questions? Ask the ACAA Technical Agent