Version 1.2 of ai05s/ai05-0061-1.txt

Unformatted version of ai05s/ai05-0061-1.txt version 1.2
Other versions for file ai05s/ai05-0061-1.txt

!standard 4.10.2(27.2/2)          07-08-06 AI05-0061-1/01
!standard A.4.3(58.5/2)
!class binding interpretation 07-08-06
!status work item 07-08-06
!status received 07-06-21
!priority Low
!difficulty Easy
!qualifier Error
!subject Assume-the-worst rule needed for access-to-discriminanted checks
!summary
In a generic body, 3.10.2(27.2/2) is checked assuming that any untagged formal private or derived type has a constrained partial view.
!question
There seems to be a contract-model problem with 3.10.2(27.2/2) in the case of a generic formal discriminated type as seen from within the generic body.
Consider this example:
procedure Foo is subtype Index is Integer range 0 .. 255; Smaller_Index : constant Index := 10; Larger_Index : constant Index := 20;
generic type T1 (D : Index) is private; package G is type Ref is access all T1; Smaller : aliased T1 (Smaller_Index); Ptr : Ref; end G;
package body G is begin Ptr := Smaller'access; -- Legal? (No.) end G;
package Pkg is type T2 is private; private type T2 (D : Index := 100) is record F : String (1 .. D); end record;
package I is new G (T2); end Pkg;
package body Pkg is Larger : T2 (Larger_Index); begin I.Ptr.all := Larger; end Pkg;
begin ...; end Foo;
3.10.2(27.2/2) is satisfied at the line marked "Legal?", because T1 does not have a partial view. This allows assigning a jumbo value to a not-so-jumbo object; this is not good.
An assume-the-worst rule seems to be needed. For purposes of checking 3.10.2(27.2/2) within a generic body, it should be assumed that any untagged formal discriminated type of the generic has a constrained partial view.
!recommendation
(See Summary.)
!wording
Change 3.10.2(27.2/2) to:
* D shall be discriminated in its full view and unconstrained in any partial view, and the designated subtype of A shall be unconstrained. For the purposes of determining within a generic body whether D is unconstrained in any partial view, a subtype is is considered to have a partial view that is constrained if it is a descendant of an untagged generic formal private or derived type. In addition to the places where Legality Rules normally apply (see 12.3), this rule applies also in the private part of an instance of a generic unit.
[Editor's note: 3.10.2(28/2) already includes the boilerplate about the private part. I have to wonder if it would be better to have this apply to all of the requirements on 'Access. (Do we really want any of these unchecked in private parts? For instance, we appear to allow an access-to-variable type to point at a constant in a private part.) If we make this change, we should delete the last line of 3.10.2(28/2) and insert the following before 3.10.2(29):
In addition to the places where Legality Rules normally apply (see 12.3), these requirements apply also in the private part of an instance of a generic unit.
end Editor's note.]
!discussion
This fix is suspiciously similar to that needed for AI05-0041-1 (although that is in unrelated wording). We may want to consider trying to declare that all formal derived and formal private types are considered to have a constrained partial view when checking rules in a generic body, rather than make specific fixes all over the Standard.
A related issue is whether generic formal types are "known to be constrained" when they are designated by a dereference of a pool-specific access type. Whether or not an allocated object is unconstrained or constrained by its initial value would appear to be determined by the actual. Thus, we have the contract problem described in the question. But it seems to be a general question that would apply anywhere that the "known to be constrained" rule is used (for instance, in renaming).
It's not even clear that the properties of the actual should be used. That's typical for dyanmic semantics, but the allocation rule is defined as static semantics.
Note that the resolution of the allocation issue matters in the implementation of the containers libraries, where we have a special permission for unconstrained element types to have constrained element objects. But if such allocated objects are actually unconstrained, we don't need that permission. A tangled web we weave...
--!corrigendum 3.10.2(27.2/2)
!ACATS Test
Add an ACATS B-Test like the example in the !question.
!appendix

From: Steven W Baird
Sent: Thursday, June 21, 2007  5:10 PM

There seems to be a contract-model problem with 3.10.2(27.2/2)
in the case of a generic formal discriminated type as seen from 
within the generic body.

This problem allows the construction of an access value which
designates an unconstrained view of a constrained object.

This in turn allows, among other things, assigning a jumbo value
to a not-so-jumbo object; things go downhill rapidly from there.

Consider this example:

  procedure Foo  is
    subtype Index is Integer range 0 .. 255;
    Smaller_Index : constant Index := 10;
    Larger_Index  : constant Index := 20;

    generic
        type T1 (D : Index) is private;
    package G is
        type Ref is access all T1;
        Smaller : aliased T1 (Smaller_Index);
        Ptr     : Ref;
    end G;

    package body G is
    begin
        Ptr := Smaller'Access;
    end G;

    package Pkg is
        type T2 is private;
    private
        type T2 (D : Index := 100) is
            record
                F : String (1 .. D);
            end record;

       package I is new G (T2);
    end Pkg;

    package body Pkg is
        Larger : T2 (Larger_Index);
    begin
        I.Ptr.all := Larger;
    end Pkg;

  begin
    ...;
  end Foo;

An assume-the-worst rule seems to be needed. For purposes of checking
3.10.2(27.2/2) within a generic body, it should be assumed that any 
untagged
formal discriminated type of the generic has a constrained partial view.

This would cause the preceding example to be rejected.

If this compile-time check is viewed as being too conservative, the 
problem
could also be solved via a new runtime check (or even a post-compilation
check). The compile-time solution seems preferable.

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

From: Tucker Taft
Sent: Thursday, June 21, 2007  6:08 PM

Alternatively, we could say that objects designated by values
of type "Ref" are constrained by their initial value.  But
if we do that, we will also have to disallow converting values of
type Ref to access types that designate objects that are *not*
constrained by their initial value.  Your solution is probably
cleaner, and avoids the question of what to do if you had
a formal access type declared similarly to Ref.

I would presume that the implementer of the generic could
move Smaller'Access into the spec, and then get instantiation-time
checking rather than having the generic body rejected.

I think this means we need the usual blather that
states that 3.10.2(27.2) is checked in the private
part of an instance, plus something like:

     For the purposes of this check in a generic body,
     an untagged formal private type is presumed to
     have a constrained partial view.

I don't think we want to restrict ourselves to
"discriminated" formals, since "(<>)" indicates
the formal is indefinite without making it
"discriminated."  But perhaps it is irrelevant
since you can't create a non-matching subtype
in that case.

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

From: Steven W Baird
Sent: Friday, June 22, 2007  2:50 PM

This sounds good except for one detail: the rule
should not be restricted to formal private types.
Formal derived types need to be included as well
because the "has a constrained partial view" property
is not preserved by derivation.

Consider the following variation on the original example:

  procedure Foo2 is
    subtype Index is Integer range 0 .. 255;
    Smaller_Index : constant Index := 10;
    Larger_Index  : constant Index := 20;

    type Has_No_Constrained_Partial_View (D : Index := 100) is
        record
            F : String (1 .. D);
        end record;

    generic
        type T1 is new Has_No_Constrained_Partial_View;
    package G is
        type Ref is access all T1;
        Smaller : aliased T1 (Smaller_Index);
        Ptr     : Ref;
    end G;

    package body G is
    begin
        Ptr := Smaller'Access;
    end G;

    package Pkg is
        type Has_A_Constrained_Partial_View is private;
    private
        type Has_A_Constrained_Partial_View is
           new Has_No_Constrained_Partial_View;

        package I is new G (Has_A_Constrained_Partial_View);
    end Pkg;

    package body Pkg is
        Larger : Has_A_Constrained_Partial_View (Larger_Index);
    begin
        I.Ptr.all := Larger;
    end Pkg;
  begin
    ...;
  end Foo2;

I'd certainly agree that this is, to quote Randy's recent
description, "another Baird anomaly that no one in their
right mind would ever try to use", but we should still
get the definition right.

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

Questions? Ask the ACAA Technical Agent