Version 1.7 of ai05s/ai05-0008-1.txt

Unformatted version of ai05s/ai05-0008-1.txt version 1.7
Other versions for file ai05s/ai05-0008-1.txt

!standard 3.3(23)          07-10-01 AI05-0008-1/05
!standard 3.10.2(26/2)
!standard 4.1(9)
!standard 6.4.1(17)
!standard 8.5.1(5/2)
!class binding interpretation 06-03-17
!status ARG Approved 6-0-4 07-06-02
!status work item 06-12-14
!status ARG Approved 9-0-3 06-11-18
!status work item 06-03-17
!status received 05-10-13
!priority High
!difficulty Medium
!qualifier Error
!subject General access values that might designate constrained objects
!summary
(See recommendation.)
!question
What should happen if the target of the assignment is an unconstrained aliased object or component and the source value would change the discriminants? (Raise C_E.) For example, given the following types:
type Rec (D : Boolean := False) is record case D is when False => I : aliased Integer; when True => C : Character; end case; end record;
type Acc_Rec is access all Rec;
consider these objects:
R : aliased Rec;
Acc_R : Acc_Rec := R'access;
and an assignment such as:
Acc_R.all := (D => True, C => 'X');
The Ada 2005 RM implies that this assignment should succeed without raising an exception. The actual subtype of the left-hand side is determined by the designated object (R), and since R's actual subtype is the unconstrained subtype Rec, the object is unconstrained and so the (implicit) conversion of the right-hand side to the subtype of Acc_R.all shouldn't require a check.
This is obviously not right, as it would require including a 'constrained bit with all aliased objects.
There is a related issue with renaming of a depends-on-discriminant component.
O : Natural renames Acc_R.I; -- OK? (Illegal.)
Here, we don't know at compile-time whether Acc_R designates a constrained object or an unconstrained object. If it's unconstrained, the renames clearly cannot be allowed (else the component would disappear).
Similar issues arise for 'Access.
!recommendation
Redo 4.1(9) to require that discriminants not be changed through the dereference of an access type that might designate an object that is constrained by its initial value.
Define the term "known to be constrained" and redo the wording of 3.10.2(26/2) and 8.5.1(5/2) to require that an object must be "known to be constrained" before components that depend on discriminants may be either renamed or used as the prefix of an Access attribute.
Specify that passing a discriminated object as an actual parameter where the nominal subtype of the corresponding formal parameter is constrained and then modifying a discriminant of the actual before the call has completed results in erroneous execution.
!wording
Add after 3.3(23):
A view of a composite object is "known to be constrained" if:
- its nominal subtype is constrained, and is not an untagged partial view; or - its nominal subtype is indefinite; or - its type is a protected type, a task type, or an explicitly limited record type; or - it is part of a stand-alone constant (including a generic formal object of mode in); or - it is part of a formal parameter of mode in; or - it is part of the object denoted by a function_call or aggregate; or - it is part of a constant return object of an extended_return_statement; or - it is a dereference of a pool-specific access type, and there is no partial view of
its type that is constrained.
AARM NOTE: We do not include dereferences of general access types because they might denote stand-alone aliased unconstrained variables. That's true even for access-to-constant types. END AARM Note.
For the purposes of determining within a generic body whether an object is known to be constrained, a subtype is not considered indefinite if it is a descendant of an untagged generic formal derived type, nor is an access type considered pool-specific if it is a descendant of a formal access type.
Replace 3.10.2(26/2):
The view shall not be a subcomponent that depends on discriminants of a variable whose nominal subtype is unconstrained, unless this subtype is indefinite, or the variable is constrained by its initial value.
with the following:
The view shall not be a subcomponent that depends on discriminants of an object unless the object is known to be constrained. In addition to the places where Legality Rules normally apply, this rule applies also in the private part of an instance of a generic unit.
Modify 4.1(9) as follows:
If the type of the name in a dereference is some access-to-object type T, then the dereference denotes a view of an object, the nominal subtype of the view being the designated subtype of T. {If the designated subtype has unconstrained discriminants, the (actual) subtype of the view is constrained by the values of the discriminants of the designated object, except when there is a partial view of the type of the designated subtype that does not have discriminants, in which case the dereference is not constrained by its discriminant values.}
AARM NOTE (added after the Ada 95 ones):
The last sentence is different from Ada 95; it is necessary because general access types can designate unconstrained objects in Ada 2005 (that was not possible in Ada 95). Thus, the rules that had this effect in Ada 95 (the object being constrained by its initial value) don't work in Ada 2005 and we have to say this explicitly.
The "except" part of the last sentence prevents privacy "breaking", so that if a private type has discriminants only in the full view, they don't interfere with freely interassigning values between objects of the type, even when the objects live in the heap.
Retain the AARM note 4.1(9.d/2) from the Ada 2005 AARM.
Add after 6.4.1(17):
Erroneous Execution
If the nominal subtype of a formal parameter with discriminants is constrained or indefinite, and the parameter is passed by reference, then the execution of the call is erroneous if the value of any discriminant of the actual is changed while the formal parameter exists (that is, before leaving the corresponding callable construct).
Replace 8.5.1(5/2):
The renamed entity shall not be a subcomponent that depends on discriminants of a variable whose nominal subtype is unconstrained, unless this subtype is indefinite, or the variable is constrained by its initial value. A slice of an array shall not be renamed if this restriction disallows renaming of the array. In addition to the places where Legality Rules normally apply, these rules apply also in the private part of an instance of a generic unit. These rules also apply for a renaming that appears in the body of a generic unit, with the additional requirement that even if the nominal subtype of the variable is indefinite, its type shall not be a descendant of an untagged generic formal derived type.
with the following:
The renamed entity shall not be a subcomponent that depends on discriminants of an object whose nominal subtype is unconstrained unless the object is known to be constrained. A slice of an array shall not be renamed if this restriction disallows renaming of the array. In addition to the places where Legality Rules normally apply, these rules apply also in the private part of an instance of a generic unit.
[Note: The last sentence of the original paragraph is redundant with the new text in 3.3, and thus is removed.]
!example
The need for the 6.4.1 change is illustrated by the following example:
declare type Component is tagged null record;
type By_Reference (D : Boolean := False) is record C : Component; end record;
subtype Constrained is By_Reference (False);
Global_To_P : By_Reference;
procedure P (X : Constrained) is begin Global_To_P := (D => True, C => <>); -- erroneous pragma Assert (X in Constrained); -- ok to generate no code for pragma end P; begin P (Global_To_P); end;
This was intended to be covered by 3.7.2(4), but that rule doesn't apply to an IN parameter passed by reference as the parameter itself is not a name denoting a subcomponent that depends on discriminants (the actual parameter might be, but the formal parameter is not a subcomponent).
The new wording for 6.4.1 needs to include "indefinite" so that problems with untagged derived types are covered. Consider:
package P is pragma Elaborate_Body; type T (D : Integer) is private; private type T (D : Integer) is tagged record C : String (1 .. D); end record; end P;
with P; package Q is type NT (ND : Integer := 3) is new T (ND); X : NT; Y : NT (0); end Q;
with Q, Ada.Text_IO; package body P is procedure P2 (Z : in out T) is -- Assume pass-by-reference C_Ren : Character renames Z.C(2); -- OK, Z is indefinite.
begin Q.X := Q.Y; -- Erroneous. Ada.Text_IO.Put (C_Ren); -- Doesn't exist anymore.
end P2;
begin P2 (T(Q.X)); -- OK. end P;
!discussion
The word "object" is used instead of "variable" in the new wording for 3.10.2(26/2) and 8.5.2(5/2). This excludes constants which are not known to be constrained, such as access-to-constant dereferences. The definition of "known to be constrained" includes the case of an in-mode subprogram parameter with an unconstrained nominal subtype. This opens the door slightly for misuse of the Unchecked_Access attribute, but it is no worse than what can be done with a formal parameter whose nominal subtype is constrained. In both cases, the problem would be the conversion of a reference to a subcomponent of a parameter that depends on discriminants into a value of a global access type which outlives the subprogram call. After the call has terminated, the enclosing object is modified so that the referenced subcomponent no longer exists. The existing wording of 13.10(1) seems sufficiently general to handle this case.
In an effort to keep the wording as simple as possible, the definition of "known to be constrained" does not mention some cases (e.g., view conversions, the current instance of a type, implementation-defined attributes, objects of a generic formal discriminated private type) which are irrelevant in the two places where this term is used. Following this reasoning, the words "or aggregate" could be deleted from the definition (although echoing the wording of AI05-0015 seems nice) as well as the mention of "a task type," (which follows 3.10(9/2)), and "and is not an untagged partial view" (which seems valuable to avoid confusion about uncovered cases).
!corrigendum 3.3(23)
Insert after the paragraph:
At the place where a view of an object is defined, a nominal subtype is associated with the view. The object's actual subtype (that is, its subtype) can be more restrictive than the nominal subtype of the view; it always is if the nominal subtype is an indefinite subtype. A subtype is an indefinite subtype if it is an unconstrained array subtype, or if it has unknown discriminants or unconstrained discriminants without defaults (see 3.7); otherwise the subtype is a definite subtype (all elementary subtypes are definite subtypes). A class-wide subtype is defined to have unknown discriminants, and is therefore an indefinite subtype. An indefinite subtype does not by itself provide enough information to create an object; an additional constraint or explicit initialization expression is necessary (see 3.3.1). A component cannot have an indefinite nominal subtype.
the new paragraphs:
A view of a composite object is known to be constrained if:
!corrigendum 3.10.2(26/2)
Replace the paragraph:
by:
!corrigendum 4.1(9)
Replace the paragraph:
If the type of the name in a dereference is some access-to-object type T, then the dereference denotes a view of an object, the nominal subtype of the view being the designated subtype of T.
by:
If the type of the name in a dereference is some access-to-object type T, then the dereference denotes a view of an object, the nominal subtype of the view being the designated subtype of T. If the designated subtype has unconstrained discriminants, the (actual) subtype of the view is constrained by the values of the discriminants of the designated object, except when there is a partial view of the type of the designated subtype that does not have discriminants, in which case the dereference is not constrained by its discriminant values.
!corrigendum 6.4.1(17)
Insert after the paragraph:
After normal completion and leaving of a subprogram, for each in out or out parameter that is passed by copy, the value of the formal parameter is converted to the subtype of the variable given as the actual parameter and assigned to it. These conversions and assignments occur in an arbitrary order.
the new paragraph:
Erroneous Execution
If the nominal subtype of a formal parameter with discriminants is constrained or indefinite, and the parameter is passed by reference, then the execution of the call is erroneous if the value of any discriminant of the actual is changed while the formal parameter exists (that is, before leaving the corresponding callable construct).
!corrigendum 8.5.1(5/2)
Replace the paragraph:
The renamed entity shall not be a subcomponent that depends on discriminants of a variable whose nominal subtype is unconstrained, unless this subtype is indefinite, or the variable is constrained by its initial value. A slice of an array shall not be renamed if this restriction disallows renaming of the array. In addition to the places where Legality Rules normally apply, these rules apply also in the private part of an instance of a generic unit. These rules also apply for a renaming that appears in the body of a generic unit, with the additional requirement that even if the nominal subtype of the variable is indefinite, its type shall not be a descendant of an untagged generic formal derived type.
by:
The renamed entity shall not be a subcomponent that depends on discriminants of an object whose nominal subtype is unconstrained unless the object is known to be constrained. A slice of an array shall not be renamed if this restriction disallows renaming of the array. In addition to the places where Legality Rules normally apply, these rules apply also in the private part of an instance of a generic unit.
!ACATS test
An ACATS B-Test and an ACATS C-Test should be created to test these cases.
!appendix

From: Gary Dismukes
Date: Monday, February 20, 2006  7:45 AM

In the process of working on part of AI-363 in GNAT I've uncovered what
appear to be some semantic problems relating to the changes for aliased
components and declared objects: specifically, the rule changes permitting
them to be unconstrained when their type has defaulted discriminants
(that is, no longer requiring them to be constrained by their initial
values).

I'm interested to see if others agree that there are problems with the RM
rules, or whether I'm just misunderstanding or overlooking something and
simply confused. :-)

Problem #1:

The first issue has to do with assignments through access values when
the designated type is unconstrained with defaulted discriminants.

What should happen if the target of the assignment is an unconstrained
aliased object or component and the source value would change the
discriminants?  For example, given the following types:

   type Rec (D : Boolean := False) is record
      case D is
         when False => I : aliased Integer;
         when True  => C : Character;
      end case;
   end record;

   type Acc_Rec is access all Rec;

consider these objects:

   R : aliased Rec;

   Acc_R : Acc_Rec := R'Access;

and an assignment such as:

   Acc_R.all := (D => True, C => 'X');

I believe the RM implies that this assignment should succeed without raising
an exception.  The actual subtype of the left-hand side is determined by the
designated object (R), and since R's actual subtype is the unconstrained
subtype Rec, the object is unconstrained and so the (implicit) conversion of
the right-hand side to the subtype of Acc_R.all shouldn't require a check.

The problem here is that we no longer know at compile time whether Acc_R.all
is constrained, and so the "constrainedness" of the target has to be a
run-time determination.  Obviously that's not the answer we want, since this
would imply having to store an implicit Constrained flag with all aliased
objects of type Rec, something that was never necessary in Ada 83/95.

It seems clear that what's needed is an assume-the-worst rule, so that
assignments through a dereference _always_ treat the target as if it were
"constrained by its initial value" in the case where the designated type
has defaulted discriminants, even though some designated objects might
actually be unconstrained.  I suppose it was the intent that assignments
always be checked in this case, but it doesn't follow from the rules as
far as I can tell.  (Note that of course we don't want this to apply
when the designated type has a partial view that is constrained, in which
case even allocated objects can be unconstrained and have their discriminants
changed, which is one of the principal semantic changes made by AI-363.)

Problem #2:

AI-363 also changes the rules for when it's legal to rename or apply
'Access to a subcomponent that depends on a discriminant.  Specifically,
3.10.2(26/2) and 8.5.1(5/2) are revised so that they no longer allow this
for aliased (enclosing) variables in general, but rather limit the allowance
to cases where the variable is "constrained by its initial value".

Consider the following example based on the earlier declarations.
The type Rec has a discriminant-dependent component I (declared aliased
to permit 'Access), and let's assume the aliased object R again:

   R : aliased Rec;  -- Default initialized and unconstrained in Ada 2005

Now what happens if we rename or apply 'Access to R's integer component:

   Renamed_Int : Integer renames R.I;

   type Acc_Int is access all Integer;
   Accessed_Int : Acc_Int := R.I'Access;

The above are both legal in Ada 95, but illegal in Ada 2005, because R
is unconstrained, and so its discriminant can change.  These are both
acknowledged incompatibilities.  (These can be worked around by either
adding an explicit constraint to the declaration of R, or by making
the less localized change of removing the defaults from the type's
discriminants.)

Now let's consider similar cases, but where the prefix is a dereferenced
access value:

   Acc_R : Acc_Rec := R'Access; -- or could be ":= new Rec'(False, 7)"

   Renamed_Int : Integer renames Acc_R.I;
     -- OK in Ada 95; but in Ada 05??

   Access_Int : Acc_Int := Acc_R.I'Access;
     -- OK in Ada 95; but in Ada 05??

Again, the above two declarations are both legal in Ada 95, but what
about Ada 2005?  Well, because of the changes to rules 3.10.2(26/2)
and 8.5.1(5/2), we have to answer the question of whether the object
Acc_R.all is "constrained by its initial value".  If the answer to
that is "yes", then the declarations are legal, and if it's "no" then
they're illegal.  As in the earlier assignment example, the problem
is again that we don't know at compile time.  If the object was
created by an allocator, then the answer is yes, but if Acc_R denotes
an aliased object declared by an (unconstrained) object declaration
then the answer is no.  So it would again seem that we need to have
an assume-the-worst rule.  Here we have to assume that the object
Acc_R.all is not constrained by its initial value, that is, we need
to assume it could be unconstrained (the opposite of the assumption
need in the dereferenced assignment case discussed above).

It seems clear to me that 3.10.2(26/2) and 8.5.1(5/2) are broken.
The use of the phrase "constrained by its initial value", replacing
"aliased" in these rules, just doesn't fly for a static semantic rule,
since this characteristic is no longer known at compile time in the
case of dereferenced access values (unless the type has a constrained
partial view...).  (I'm not sure what the right fix is here.  We want
to say something like "might be constrained by its initial value",
though I don't think that would be acceptable RM-ese.  Maybe we have
to add an extra statement along the lines "If the variable is a
dereferenced access value, then the variable is presumed to be
constrained by its initial value", though we also have to make
sure to exempt the case where there's a constrained partial view.)

----

In summary, it seems that the extra flexibility of being able to declare
unconstrained aliased objects creates two problems.  Assignments still
need to do constraint checks (when done through access values) even
though the target might really be unconstrained, and cases of renamings
and 'Access that were legal in Ada 95 become illegal even when they might
be safe (such as when the dereferenced object was created by an allocator).

Using a worst-case rule for the assignment case doesn't seem like a big deal,
since it's consistent with assignments through access values in Ada pre-2005,
though it's perhaps a little surprising that assigning to an aliased object
through a formal parameter should behave differently than assignment to that
same object through an access value.  In any case, I believe this requires
a correction to the current rules, since otherwise the RM seems to imply
a need for a constrained flag within objects.

What concerns me more is the case of 'Access applied to subcomponents of
an aliased object, where we have an incompatiblity in the access dereference
case that's not necessarily easy to work around (unlike cases involving
aliased stand-alone objects, where you can just add a discriminant
constraint to avoid the incompatibility).  The only available workaround
in the dereferencing case appears to be to remove discriminant defaults,
but that may not be feasible in applications that have a significant
dependence on declaring mutable objects.

The only alternative I see at the moment to adding worst-case corrections
to the rules would be to limit the cases where objects and components
can be unconstrained to when the type has a constrained partial view.
This would have the benefit of limiting the incompatibilities and would
be consistent with the main thrust of the AI, but might be considered
overly restrictive, since we'd lose the (mostly) nice ability to have
unconstrained aliased objects for all types with defaulted discriminants.

Thoughts?

****************************************************************

From: Randy Brukardt
Date: Monday, February 20, 2006  5:52 PM

...
> I'm interested to see if others agree that there are problems with the RM
> rules, or whether I'm just misunderstanding or overlooking something and
> simply confused. :-)

I think you're confused, but you've confused me enough that I'm not
absolutely certain.

> Problem #1:
>
> The first issue has to do with assignments through access values when
> the designated type is unconstrained with defaulted discriminants.
>
> What should happen if the target of the assignment is an unconstrained
> aliased object or component and the source value would change the
> discriminants?  For example, given the following types:
>
>    type Rec (D : Boolean := False) is record
>       case D is
>          when False => I : aliased Integer;
>          when True  => C : Character;
>       end case;
>    end record;
>
>    type Acc_Rec is access all Rec;

This has to be a private type to trigger these rules; they don't happen for
non-private types. That's critical to making them work, because most of the
things you are worrying about can't happen outside of the package body.

I found out how critical that is when trying to explain these rules to John
for the Rationale. If you leave out the privateness, none of it makes any
sense.

I.e., you need a constrained private type here:

package P is
    type Rec is private;
private
    type Rec (D : Boolean := False) is record
       case D is
          when False => I : aliased Integer;
          when True  => C : Character;
       end case;
    end record;

    type Acc_Rec is access all Rec;
end;

> consider these objects:
>
>    R : aliased Rec;
>
>    Acc_R : Acc_Rec := R'Access;
>
> and an assignment such as:
>
>    Acc_R.all := (D => True, C => 'X');
>
> I believe the RM implies that this assignment should succeed without raising
> an exception.  The actual subtype of the left-hand side is determined by the
> designated object (R), and since R's actual subtype is the unconstrained
> subtype Rec, the object is unconstrained and so the (implicit) conversion of
> the right-hand side to the subtype of Acc_R.all shouldn't require a check.

Yes, of course. (With the revised types. With the original types, the rules
aren't changed for this, and the Constraint_Error still happens - the object
appears to be constrained by its initial value.)

> The problem here is that we no longer know at compile time whether Acc_R.all
> is constrained, and so the "constrainedness" of the target has to be a
> run-time determination.  Obviously that's not the answer we want, since this
> would imply having to store an implicit Constrained flag with all aliased
> objects of type Rec, something that was never necessary in Ada 83/95.

Why do you say this? There isn't anything that could be on the LHS that
could be constrained. You've not provided any example, and I don't think you
can...

...
> Problem #2:
>
> AI-363 also changes the rules for when it's legal to rename or apply
> 'Access to a subcomponent that depends on a discriminant.  Specifically,
> 3.10.2(26/2) and 8.5.1(5/2) are revised so that they no longer allow this
> for aliased (enclosing) variables in general, but rather limit the allowance
> to cases where the variable is "constrained by its initial value".

Correct.

...
> Now let's consider similar cases, but where the prefix is a dereferenced
> access value:
>
>    Acc_R : Acc_Rec := R'Access; -- or could be ":= new Rec'(False, 7)"

R is not "constrained by its initial value"! Nor is Acc_R. You need
"constant" for that to be the case for R, but that then doesn't match the
access type. And it's never the case for a variable. Note that the rules for
that were changed a lot; in particular, "aliased" no longer means
"constrained by its initial value".

Note that allocators aren't "constrained by their initial value" for these
types, either.

>    Renamed_Int : Integer renames Acc_R.I;
>      -- OK in Ada 95; but in Ada 05??
>
>    Access_Int : Acc_Int := Acc_R.I'Access;
>      -- OK in Ada 95; but in Ada 05??

These are of course illegal.

> Again, the above two declarations are both legal in Ada 95, but what
> about Ada 2005?  Well, because of the changes to rules 3.10.2(26/2)
> and 8.5.1(5/2), we have to answer the question of whether the object
> Acc_R.all is "constrained by its initial value".  If the answer to
> that is "yes", then the declarations are legal, and if it's "no" then
> they're illegal.  As in the earlier assignment example, the problem
> is again that we don't know at compile time.  If the object was
> created by an allocator, then the answer is yes, but if Acc_R denotes
> an aliased object declared by an (unconstrained) object declaration
> then the answer is no.  So it would again seem that we need to have
> an assume-the-worst rule.  Here we have to assume that the object
> Acc_R.all is not constrained by its initial value, that is, we need
> to assume it could be unconstrained (the opposite of the assumption
> need in the dereferenced assignment case discussed above).

This is throughly confused. I don't see anything anywhere in any of your
examples that is "constrained by its initial value" (that mainly happens for
"constant", and for non-private types).

****************************************************************

From: Tucker Taft
Date: Monday, February 20, 2006  6:51 PM

I think it is very nice that adding "aliased" doesn't make
as much difference as it did in Ada 95, so I would not
want to lose that feature.  I agree that "constrained
by its initial value" doesn't quite cut it as a replacement
for "aliased."  Since it is used in a static semantic
rule, clearly we need to interpret it statically.

For the purposes of constraint checks, it seems that
blah.all should be presumed constrained by its initial
value if a corresponding allocator would be.

For the purposes of renaming and 'access of discriminant-dependent
components, blah.all should be presumed unconstrained if
blah is a general access value and an aliased stand-alone
object of the designated subtype would be unconstrained.

Renaming and 'access of discriminant-dependent
components doesn't seem like a very important
capability to me, so I don't mind the loss
of functionality.

****************************************************************

From: Tucker Taft
Date: Monday, February 20, 2006  11:52 PM

Unfortunately, we can't fix this by defining whether
a dereference is "constrained by its initial value,"
because we want the answer to be different depending
on whether it is a constraint check or a renaming
or 'Access.  Instead it seems like we have to formalize
the "assume the worst" that Gary suggests.  And
probably generics interact with this as well...

So this implies we need to make the following changes:

   3.10.2(26/2)
   8.5.1(5/2)

In these places, we need to assume the worst, namely that
a dereference might denote an unconstrained object, if the
access value is a general access value and the nominal
subtype is unconstrained.

   4.1(9)

Here we need to say the subtype of a dereference is always
considered constrained by its *current* discriminant values,
unless the nominal subtype is unconstrained and there
is a partial view that is constrained.

****************************************************************

From: Gary Dismukes
Date: Tuesday, February 21, 2006  1:03 AM

> I think you're confused, but you've confused me enough that I'm not
> absolutely certain.

Sorry if what I wrote wasn't clear.  I was trying to be moderately
detailed in my explanation, without weighing it down with too much
RM exegesis.  At least Tuck understood what I was saying. :-)

> > Problem #1:
> >
> > The first issue has to do with assignments through access values when
> > the designated type is unconstrained with defaulted discriminants.
> >
> > What should happen if the target of the assignment is an unconstrained
> > aliased object or component and the source value would change the
> > discriminants?  For example, given the following types:
> >
> >    type Rec (D : Boolean := False) is record
> >       case D is
> >          when False => I : aliased Integer;
> >          when True  => C : Character;
> >       end case;
> >    end record;
> >
> >    type Acc_Rec is access all Rec;
> 
> This has to be a private type to trigger these rules; they don't happen for
> non-private types. That's critical to making them work, because most of the
> things you are worrying about can't happen outside of the package body.

Incorrect.  I think if you look carefully at what the rules say you'll
see that privateness isn't required for any of what I was talking about.
I thought I had made it clear that I wasn't referring to cases where
there was a constrained private view.  The rules have changed so that
aliased objects with defaulted discriminants can be unconstrained
even if there isn't a private type involved.

Take a close look at 3.3.1(9/2).  I've retained the old text and enclosed
it in << >> so it will stand out:

                              Dynamic Semantics

  9/2 {AI95-00363-01} {constraint (of an object)}
  If a composite object declared by an object_declaration has an unconstrained
  nominal subtype, then if this subtype is indefinite or the object is constant
  <<or aliased (see 3.10)>> the actual subtype of this object is constrained.
  The constraint is determined by the bounds or discriminants (if any) of its
  initial value; {constrained by its initial value} the object is said to be
  constrained by its initial value. {actual subtype (of an object)}
  {subtype (of an object): See actual subtype of an object} <<[In the case of
  an aliased object, this initial value may be either explicit or implicit;
  in the other cases, an explicit initial value is required.]>> When not
  constrained by its initial value, the actual and nominal subtypes of the
  object are the same. {constrained (object)} {unconstrained (object)} If its
  actual subtype is constrained, the object is called a constrained object.

The critical change here is that the rules for when an object with an
unconstrained nominal subtype is constrained no longer apply when the
object is aliased.  There's nothing mentioned here about private views.

This change was quite intentional in AI-363 AFAIK, and at least Tucker
also seems to agree that was the intent.

> I found out how critical that is when trying to explain these rules to John
> for the Rationale. If you leave out the privateness, none of it makes any
> sense.

I wouldn't go so far as to say it doesn't make any sense, but it does lead
to the problems I was trying to describe (apparently inadequately). :-)

> I.e., you need a constrained private type here:
> 
> package P is
>     type Rec is private;
> private
>     type Rec (D : Boolean := False) is record
>        case D is
>           when False => I : aliased Integer;
>           when True  => C : Character;
>        end case;
>     end record;
> 
>     type Acc_Rec is access all Rec;
> end;

Again, not correct.  My examples were intended specifically to address
the nonprivate case.

> > consider these objects:
> >
> >    R : aliased Rec;
> >
> >    Acc_R : Acc_Rec := R'Access;
> >
> > and an assignment such as:
> >
> >    Acc_R.all := (D => True, C => 'X');
> >
> > I believe the RM implies that this assignment should succeed without raising
> > an exception.  The actual subtype of the left-hand side is determined by the
> > designated object (R), and since R's actual subtype is the unconstrained
> > subtype Rec, the object is unconstrained and so the (implicit) conversion of
> > the right-hand side to the subtype of Acc_R.all shouldn't require a check.
> 
> Yes, of course. (With the revised types. With the original types, the rules
> aren't changed for this, and the Constraint_Error still happens - the object
> appears to be constrained by its initial value.)

I wasn't talking about the "revised type" case (i.e., with privateness).

Given the types I meant, now you have to provide the exegesis that implies
that a constraint check is required when Acc.all denotes an unconstrained
stand-alone object, and show where the notion of "the object appears to be
constrained by its initial value" is defined.  I agree that something like
that needs to be the case, but I don't believe it follows from the rules.

> > The problem here is that we no longer know at compile time whether Acc_R.all
> > is constrained, and so the "constrainedness" of the target has to be a
> > run-time determination.  Obviously that's not the answer we want, since this
> > would imply having to store an implicit Constrained flag with all aliased
> > objects of type Rec, something that was never necessary in Ada 83/95.
> 
> Why do you say this? There isn't anything that could be on the LHS that
> could be constrained. You've not provided any example, and I don't think you
> can...

Again I'm talking about the *nonprivate* case, where some aliased objects
are constrained and some are unconstrained (though if you aren't convinced
yet that that can happen I can see why didn't understand my example).

> ...
> > Problem #2:
> >
> > AI-363 also changes the rules for when it's legal to rename or apply
> > 'Access to a subcomponent that depends on a discriminant.  Specifically,
> > 3.10.2(26/2) and 8.5.1(5/2) are revised so that they no longer allow this
> > for aliased (enclosing) variables in general, but rather limit the
> allowance
> > to cases where the variable is "constrained by its initial value".
> 
> Correct.
> 
> ...
> > Now let's consider similar cases, but where the prefix is a dereferenced
> > access value:
> >
> >    Acc_R : Acc_Rec := R'Access; -- or could be ":= new Rec'(False, 7)"
> 
> R is not "constrained by its initial value"! Nor is Acc_R. You need
> "constant" for that to be the case for R, but that then doesn't match the
> access type. And it's never the case for a variable. Note that the rules for
> that were changed a lot; in particular, "aliased" no longer means
> "constrained by its initial value".
>
> Note that allocators aren't "constrained by their initial value" for these
> types, either.

If by "these types" you mean the case where there's a constrained partial
view, you're right, and I understand that, but I'm talking about the
nonprivate case.

For that case, R is indeed not constrained, but heap-allocatred objects
*are* constrained.

> >    Renamed_Int : Integer renames Acc_R.I;
> >      -- OK in Ada 95; but in Ada 05??
> >
> >    Access_Int : Acc_Int := Acc_R.I'Access;
> >      -- OK in Ada 95; but in Ada 05??
> 
> These are of course illegal.
> 
> > Again, the above two declarations are both legal in Ada 95, but what
> > about Ada 2005?  Well, because of the changes to rules 3.10.2(26/2)
> > and 8.5.1(5/2), we have to answer the question of whether the object
> > Acc_R.all is "constrained by its initial value".  If the answer to
> > that is "yes", then the declarations are legal, and if it's "no" then
> > they're illegal.  As in the earlier assignment example, the problem
> > is again that we don't know at compile time.  If the object was
> > created by an allocator, then the answer is yes, but if Acc_R denotes
> > an aliased object declared by an (unconstrained) object declaration
> > then the answer is no.  So it would again seem that we need to have
> > an assume-the-worst rule.  Here we have to assume that the object
> > Acc_R.all is not constrained by its initial value, that is, we need
> > to assume it could be unconstrained (the opposite of the assumption
> > need in the dereferenced assignment case discussed above).
> 
> This is throughly confused. I don't see anything anywhere in any of your
> examples that is "constrained by its initial value" (that mainly happens for
> "constant", and for non-private types).

Well, I think you're confused because you keep looking at my examples
through private-tinted glasses. ;-)  If you take another look at my
examples with the understanding that these are based on regular types
with defaulted discriminants things may start to make more sense.
Of course that requires your being convinced that you can have
unconstrained aliased objects of such types.

In the *nonprivate* case, I assert that an aliased stand-alone object
can be unconstrained (hence, not "constrained by its initial value),
but heap-allocated objects of the type still are "constrained by
their initial value".  And the problem is that in the dereferenced
case you don't know statically whether or not the designated object
is constrained by its initial value, so you can't apply the legality
rules for renamings and 'Access.  Consequently, some sort of revision
is required to the rules so that they'll work for these cases, because
the current rule isn't checkable at compile-time in all cases.

****************************************************************

From: Gary Dismukes
Date: Tuesday, February 21, 2006  1:10 AM

> Unfortunately, we can't fix this by defining whether
> a dereference is "constrained by its initial value,"
> because we want the answer to be different depending
> on whether it is a constraint check or a renaming
> or 'Access.

That's right.  The "assume the worst" cuts in opposite
directions in the two cases (Problem #1 vs. #2).

> Instead it seems like we have to formalize
> the "assume the worst" that Gary suggests.  And
> probably generics interact with this as well...

Doesn't surprise me that generics come into the picture,
though I haven't thought about the implications there.

> So this implies we need to make the following changes:
> 
>    3.10.2(26/2)
>    8.5.1(5/2)
> 
> In these places, we need to assume the worst, namely that
> a dereference might denote an unconstrained object, if the
> access value is a general access value and the nominal
> subtype is unconstrained.

Yes.

>    4.1(9)
> 
> Here we need to say the subtype of a dereference is always
> considered constrained by its *current* discriminant values,
> unless the nominal subtype is unconstrained and there
> is a partial view that is constrained.

Yes.

****************************************************************

From: Pascal Leroy
Date: Tuesday, February 21, 2006  2:49 AM

I suppose that's another action item for Tuck: prepare an AI for
consideration at the Oporto meeting.

We should of course ask ourselves whether we want to fix theses problems
before sending the Amendment to WG9.  My gut feeling is that this is not
the last bug that we'll find in Ada 2005, and that it can fixed later on.
Although crafting the words may be hard, the intent is clear: we don't
want to be able to change the discriminants of constrained objects, and we
don't want to have to store a constrained bit in every mutable object.

If someone in the group thinks that we need a fix before sending the
Amendment to WG9, speak up now!

...
PS: I realize that, technically, the informal review period is over.  I
also realize that the decision of what changes go into the Amendment rests
with AXE Consultants.  But we have a moral obligation to give guidance to
AXE Consultants...

****************************************************************

From: Dan Eilers
Date: Tuesday, February 21, 2006  11:11 AM

I would be in favor of adding an RM note stating that the intent
of the rules is to disallow changing the discriminants of constrained
objects, and to avoid having to store a constrained bit in every
mutable object.

Such a note presumably could be added without any impact to the schedule,
and would provide cover for any implementer and/or textbook writer wanting
not to take the existing rules too literally.

****************************************************************

From: John Barnes
Date: Tuesday, February 21, 2006  12:09 PM

Seems a reasonable suggestion.

****************************************************************

From: Randy Brukardt
Date: Tuesday, February 21, 2006  1:51 PM

I do think we ought to do *something* now (at least in the AARM), because
the fix will require widening the incompatibility. It is important that
implementers and users be aware of that fact.

But I agree that fixing the words themselves is more likely to cause
problems than to fix them at this stage. This will need careful
consideration, not a 5-minute fix.

So, if we were to add a user note, where would it go? It seems that there
are three known places where this would have an impact, and it seems like
too much to add something to all of them. Suggestions?

****************************************************************

From: Tucker Taft
Date: Tuesday, February 21, 2006  6:05 PM

I would not bother adding a user note.  I would
add an AARM implementation note.

****************************************************************

From: Pascal Leroy
Date: Wednesday, February 22, 2006  3:12 AM

I agree.  A user note would have to say "don't trust the rules above, they
are not exactly right".  That's embarrassing for us, and confusing for the
user.  An AARM note is preferable, as it provide guidance to implementers
and textbook writers regarding the intent of the language.

****************************************************************

From: Robert Dewar
Date: Wednesday, February 22, 2006  6:46 AM

> I agree.  A user note would have to say "don't trust the rules above, they
> are not exactly right".  That's embarrassing for us

That's not a valid argument, we are not in the embarassment-avoidance 
business :-)

, and confusing for the
> user.

I don't see that a carefully written note here would be confusing.
We do seem to have a non-obvious consequence here, and I think a
note would be helpful.

   An AARM note is preferable, as it provide guidance to implementers
> and textbook writers regarding the intent of the language.

The AARM is not an official document and should not be needed by
textbook writers. it is occasionally useful for implementors,
though I often find that when I go to look for something, the
very place that needs a comment has none :-)

****************************************************************

From: John Barnes
Date: Wednesday, February 22, 2006  1:38 AM

Put the note in the place where it is most important and put references to
it in the other places.  Sounds like we need one of those To be Honest notes
or perhaps in this case To Be Dishonest.  Where are the three places?

****************************************************************

From: Gary Dismukes
Date: Wednesday, February 22, 2006  12:23 PM

The three relevant places are 4.1(9), 3.10.2(26/2), and 8.5.1(5/2).
The first is where it makes sense to centralize notes/annotations
about dereferences.

****************************************************************

From: Randy Brukardt
Date: Thursday, February 23, 2006  8:17 PM

> > I agree.  A user note would have to say "don't trust the rules above,
they
> > are not exactly right".  That's embarrassing for us
>
> That's not a valid argument, we are not in the embarrassment-avoidance
> business :-)

I agree with this.

> , and confusing for the user.
>
> I don't see that a carefully written note here would be confusing.
> We do seem to have a non-obvious consequence here, and I think a
> note would be helpful.

But disagree with this. A "carefully written note" begs the question of why
we bothered to write it instead of fixing the silly rules themselves. In any
case, I can't come up with a note that would be both understandable and
useful.

Those of you who want a user note, please suggest some wording for such a
note so that we can consider it ASAP.

>    An AARM note is preferable, as it provide guidance to implementers
> > and textbook writers regarding the intent of the language.
>
> The AARM is not an official document and should not be needed by
> textbook writers.

If they want to know "why", the AARM is a useful reference. If they don't
want to know "why", I wonder about the quality of the textbook...

> it is occasionally useful for implementers,
> though I often find that when I go to look for something, the
> very place that needs a comment has none :-)

It's probably too late to fix such things this time around. (And yes, I've
had that same experience, although mostly when writing AIs.) If you find
something that seems important, please let us know (post here or on Ada
comment) -- there is an AI including a list of things that might be fixed in
the AARM "next time". If we don't know, it certainly won't happen.

****************************************************************

From: Randy Brukardt
Date: Thursday, February 23, 2006  8:51 AM

> The three relevant places are 4.1(9), 3.10.2(26/2), and 8.5.1(5/2).
> The first is where it makes sense to centralize notes/annotations
> about dereferences.

I don't think the latter two have anything (interesting) to do with
dereferences.

The point is that a dereference is (almost) always a constrained view. I
thought that was the language rule, which is why I was so confused about
your question. It certainly ought to be the language rule.

Here's the AARM notes I added to 4.1(9):

9.c/2{AI95-00363-01} If an allocator for the access-to-object type T is one
that creates objects that are constrained by their initial value (see 4.8),
the nominal subtype is constrained even if the designated type of T is not.
We don't want the effect of the dereference to depend on the designated
object. This matters because general access-to-unconstrained can designate
both allocated objects (which are constrained at birth) and aliased stack
objects (which aren't necessarily constrained). This is a wording bug that
was discovered after the completion of Amendment 1 when it was too late to
fix it; we expect that it will be corrected by an early Ada 2005 AI.

9.d/2Implementation Note: {AI95-00363-01} Since we don't depend on whether
the designated object is constrained, it is not necessary to include a
constrained bit in every object that could be designated by a general access
type.

And for 3.10.2(26/2):

26.h/2To be honest: {AI95-00363-01} If X is a subcomponent that depends on
discriminants, and the subcomponent is a dereference of a general access
type whose designated type is unconstrained and whose allocators create
objects that are constrained by their initial values (see 4.8), the view is
illegal. This is necessary as such a general access type can designate an
unconstrained (stack) object, and we can't have legality depending on the
designated object (as that is not known at compile-time). This is a wording
bug that was discovered after the completion of Amendment 1 when it was too
late to fix it; we expect that it will be corrected by an early Ada 2005 AI.

And for 8.5.1(5/2):

26.h/2To be honest: {AI95-00363-01} If the renamed entity is a subcomponent
that depends on discriminants, and the subcomponent is a dereference of a
general access type whose designated type is unconstrained and whose
allocators create objects that are constrained by their initial values (see
4.8), the view is illegal. This is necessary as such a general access type
can designate an unconstrained (stack) object, and we can't have legality
depending on the designated object (as that is not known at compile-time).
This is a wording bug that was discovered after the completion of Amendment
1 when it was too late to fix it; we expect that it will be corrected by an
early Ada 2005 AI.

Improvements welcome.

****************************************************************

From: Tucker Taft
Date: Friday, February 24, 2006  2:21 PM

> Here's the AARM notes I added to 4.1(9):
> 
> 9.c/2{AI95-00363-01} If an allocator for the access-to-object type T is one
> that creates objects that are constrained by their initial value (see 4.8),
> the nominal subtype is constrained even if the designated type of T is not.

Oh dear, you don't want to change the nominal subtype.  It must
remain as it is.  What you want to say is that the *subtype* of
the view, not the "nominal subtype," is constrained.  It is the
subtype, not the nominal subtype, that determines the 'Constrained
bit.  It is the subtype of the target object, not the nominal
subtype of the target object, that is the subtype to which
the RHS of an assignment is converted.

...
 
> And for 3.10.2(26/2):
> 
> 26.h/2To be honest: {AI95-00363-01} If X is a subcomponent that depends on
> discriminants, and the subcomponent is a dereference of a general access
> type whose designated type is unconstrained and whose allocators create
> objects that are constrained by their initial values (see 4.8), the view is
> illegal.

You can make this a bit simpler by simply saying that for a discrmininant
dependent subcomponent of a dereference of a general access subtype,
if the designated subtype has unconstrained discriminants with defaults,
'Access is not permitted.

...
> And for 8.5.1(5/2):
> 
> 26.h/2To be honest: {AI95-00363-01} If the renamed entity is a subcomponent
> that depends on discriminants, and the subcomponent is a dereference of a
> general access type whose designated type is unconstrained and whose
> allocators create objects that are constrained by their initial values (see
> 4.8), the view is illegal. This is necessary as such a general access type
> can designate an unconstrained (stack) object, and we can't have legality
> depending on the designated object (as that is not known at compile-time).
> This is a wording bug that was discovered after the completion of Amendment
> 1 when it was too late to fix it; we expect that it will be corrected by an
> early Ada 2005 AI.

Again, I would simply say that if the designated subtype is
unconstrained with defaults for discriminants, the renaming
is illegal.

****************************************************************

From: Randy Brukardt
Date: Thursday, February 24, 2006  8:19 PM

...
> Oh dear, you don't want to change the nominal subtype.  It must
> remain as it is.  What you want to say is that the *subtype* of
> the view, not the "nominal subtype," is constrained.  It is the
> subtype, not the nominal subtype, that determines the 'Constrained
> bit.  It is the subtype of the target object, not the nominal
> subtype of the target object, that is the subtype to which
> the RHS of an assignment is converted.

OK, I dropped the word "nominal".

...
> > And for 3.10.2(26/2):
> >
> > 26.h/2To be honest: {AI95-00363-01} If X is a subcomponent that depends on
> > discriminants, and the subcomponent is a dereference of a general access
> > type whose designated type is unconstrained and whose allocators create
> > objects that are constrained by their initial values (see 4.8), the view is
> > illegal.
>
> You can make this a bit simpler by simply saying that for a discrmininant
> dependent subcomponent of a dereference of a general access subtype,
> if the designated subtype has unconstrained discriminants with defaults,
> 'Access is not permitted.

OK. "and has discriminants with defaults". (I don't like saying
"unconstrained discriminants", because it sounds like the discriminants are
unconstrained, not the type with them.)

> > ... This is necessary as such a general access type can designate an
> > unconstrained (stack) object, and we can't have legality depending on the
> > designated object (as that is not known at compile-time). This is a wording
> > bug that was discovered after the completion of Amendment 1 when it was too
> > late to fix it; we expect that it will be corrected by an early Ada 2005 AI.

I've concluded that this isn't really a wording bug (although it would be
best to change the wording to be clear). The wording says "unless ... the
variable is constrained by its initial value". This is not true for a
general access type as above;
you can't know whether it is or not (and this is a legality rule), the rule
says "is", not "might"! So I changed the paragraph to:

To be honest: {AI95-00363-01} If X is a subcomponent that depends on
discriminants, and the subcomponent is a dereference of a general access
type whose designated type is unconstrained and whose discriminants have
defaults, the attribute is illegal. Such a general access type can designate
an unconstrained (stack) object. Since such a type might not designate an
object constrained by its initial value, the 'Access is illegal — the rule
says “is” constrained by its initial value, not “might be” constrained by
its initial value. No other interpretation makes sense, as we can't have
legality depending on something (which object is designated) that is not
known at compile-time, and we surely can't allow this for unconstrained
objects. The wording of the rule should be much clearer on this point, but
this was discovered after the completion of Amendment 1 when it was too late
to fix it.

[I still expect that we'll fix it, but there's no critical reason to do so
here; only 4.1(9) is actually wrong.]

> > And for 8.5.1(5/2):

Same changes here.

****************************************************************

Summary of private e-mail of December 13-14, 2006
Involving Randy Brukardt, Pascal Leroy, and Stephen Baird.

We accidentally uncovered a new problem with the AI. Here's the sequence of events:

Randy thought a rule was missing from the AI, and asked Pascal and Steve
about it, appending an example from AI95-184 showing the need for the rule.
Unfortunately, he appended the *wrong* example from that AI (there are two),
commenting that it showed that view conversions might actually matter in the
3.3(23) rules.

Pascal replied that this is handled properly by the language, and there isn't
any view conversion in the example, but that there was a way to get the
effect of a view conversion for that example.

Randy ignored most of Pascal's note and sent the correct example (which was
about generics).

Steve pointed out that the needed wording is in fact in the AI (although
Randy missed it completely). He then went on to comment that Pascal's example
is in fact a real problem, and suggested a solution based on it being part
of the second example Randy sent (rather than the first).

Randy responded extensively to Steve's note before realizing that Pascal's
example was meant to be part of the *first* example sent. And it wasn't quite
legal, as it was missing a conversion: in fact a view conversion, the one
that prompted the example in the first place.

The net effect is an amazingly confused thread of e-mail. So just a summary of
what actually matters is presented here.

-------------------------------------------------------------------

Consider the following example (based on AI95-184).

    package P is
       pragma Elaborate_Body;
       type T (D : Integer) is private;
    private
       type T (D : Integer) is tagged
          record
             C : String (1 .. D);
          end record;
    end P;
 
    with P;
    package Q is
       type NT (ND : Integer := 3) is new T (ND);
       X : NT;
       Y : NT (0);
    end Q
 
    with Q, Ada.Text_IO;
    package body P is
	procedure P2 (Z : in out T) is -- Assume pass-by-reference
	   C_Ren : Character renames Z.C(2);
	begin
	   Q.X := Q.Y;
           Ada.Text_IO.Put (C_Ren); -- Ouch, C_Ren no longer exists.
	end P2;
	
    begin
        P2 (T(Q.X)); -- OK.
    end P;

Note that T(Q.X) is a view conversion in this context. If we're assuming
pass-by-reference, then we have a situation very similar to the one for
constrained parameters.

Pascal suggested changing 6.4.1(17.1) to say "constrained or indefinite",
so that the new rule would also apply to this case.

****************************************************************

Questions? Ask the ACAA Technical Agent