Version 1.4 of ai12s/ai12-0027-1.txt

Unformatted version of ai12s/ai12-0027-1.txt version 1.4
Other versions for file ai12s/ai12-0027-1.txt

!standard 4.6(8/2)          12-07-15 AI12-0027-1/02
!standard 4.6(24.8/2)
!class binding interpretation 12-06-04
!status work item 12-06-04
!status received 12-04-09
!priority Low
!difficulty Medium
!subject Contract violation for aliased components of actuals for formal array types
!summary
An additional "assume-the-worst" Legality Rule is adopted to avoid the problem noted in the question.
!question
Type conversions from array types with unaliased components to array types with aliased components (4.6(24.8)) are prohibited, in order to prevent the discriminant of an aliased discriminated component from being modified. 4.6(8) says that for a view conversion used as an OUT or IN OUT actual parameter, the types have to be convertible both ways, which means that an array type with aliased components can't be converted to an array type with unaliased components either.
However, it seems that you can get around this by using generics, since by 12.5.3(8) and AARM 12.5.3(8.a) it's OK if a formal array type's components are unaliased and the actual's are aliased, and Legality Rules such as 4.6(24.8) aren't checked in an instance body.
This creates a hole which should be fixed, right? (Yes.)
!recommendation
(See summary.)
!wording
append to 4.6(8/2):
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.
TBD: do we need similar boilerplate for 21/3 and 24/3? Let's wait until a need is demonstrated.
append after 4.6(24.8/2), as another bulleted list item:
- if the Target_Type of a view conversion is a generic formal array
type of a generic unit G that does not have aliased components, then the conversion shall not occur within the body of G, nor within the body of a generic unit declared within the declarative region of G.
TBD: this is the 4th occurrence of this somewhat opaque "within the body of a of a generic unit declared within" wording. See 8.5.1, 8.5.4, and 12.6. do we want to define a term like "the extended body" of a generic unit and then use that term in these 4 places?
!discussion
There seem to be four possibilities, none of which seem very good:
(1) Modify the matching rule to require that the aliased (or not) state of the components match exactly. This is probably what the rule ought to have been, but it is incompatible. Moreover, such a rule would require having an extra version of generic sort routines and the like just to support the possibility that the components are aliased. Bleech!!
(2) Use an assume-the-worst rule in generic bodies for the problematic type conversions. That is, array type conversions would essentially be banned for types derived from generic formal types unless the formal type had aliased components. This seems pretty draconian.
(3) Use the old "raise Program_Error for a contract violation" trick. That is, have a array type conversion raise Program_Error if the target components are aliased and the source components are not (or vice-versa). This would work but would provide a "tripping hazard" that could easily be missed in testing of a reusable component (the component would only fail with specific parameter types).
(4) Determine if we really need the rule at all, as the original reason was to prevent the changing of a discriminant of an aliased component (something we no longer try to prohibit in general, because there always were holes in the rules). So perhaps we don't need the strong conversion rule. But this seems like a large can of worms to open up.
We chose (2), as this avoids any run-time overhead. Any such type conversions could be moved to the specification as a workaround, using a helper "expression function". (3) would require run-time overhead for this rare case (although it would be limited to the case itself unless generic code sharing is used by the implementation). (1) would prevent the use of Ada.Containers.Generic_Array_Sort with arrays of aliased components, which seems insane given that procedure probably doesn't use any problematic type conversions. (4) just seems too dangerous (and eliminating the type conversion rule was considered and rejected for Ada 2005, so it seems likely that it is still need).
!ACATS test
An ACATS B-Test should be created to test these rules.
!appendix

!topic Aliased components: generic contract model violation?
!reference 4.6(24.8), 4.6(8), 12.5.3(8)
!from Adam Beneschan 12-04-09
!discussion

Consider:

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

package Pack1 is
    type T (D : Integer := 0) is null record;
    type T_Arr is array (Natural range <>) of T;  -- unaliased components
    procedure Increment_Discriminant (Arr : in out T_Arr; Index : Natural);
end Pack1;

package body Pack1 is
    procedure Increment_Discriminant (Arr : in out T_Arr; Index : Natural) is
    begin
        Arr (Index) := (D => Arr (Index).D + 1);
    end Increment_Discriminant;
end Pack1;

with Pack1;
package Pack2 is
    type My_Arr is array (Natural range <>) of aliased Pack1.T;
end Pack2;

with Pack2;
package Pack3 is
    procedure Illegal (Arr : in out Pack2.My_Arr; Index : Natural);
end Pack3;

with Pack1;
package body Pack3 is
    procedure Illegal (Arr : in out Pack2.My_Arr; Index : Natural) is
    begin
        Pack1.Increment_Discriminant (Pack1.T_Arr (Arr), Index);
            -- view conversion illegal by 4.6(24.8) and 4.6(8)
    end Illegal;
end Pack3;

with Pack1;
generic
    type Formal_Arr is array (Natural range <>) of Pack1.T; package Pack4 is
    procedure Mess_With (Arr : in out Formal_Arr; Index : Natural);
end Pack4;

package body Pack4 is
    procedure Mess_With (Arr : in out Formal_Arr; Index : Natural) is
    begin
        Pack1.Increment_Discriminant (Pack1.T_Arr (Arr), Index);
    end Mess_With;
end Pack4;

with Pack2;
with Pack4;
package Pack5 is
    package New_Pack4 is new Pack4 (Pack2.My_Arr);
        -- generic contract model violation?
end Pack5;

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

As I understand it, a rule was added in AI95-168 and AI95-363 to prohibit type
conversions from array types with unaliased components to array types with
aliased components (4.6(24.8)), in order to prevent the discriminant of an
aliased discriminated component from being modified.  4.6(8) says that for a
view conversion used as an OUT or IN OUT actual parameter, the types have to be
convertible both ways, which means that an array type with aliased components
can't be converted to an array type with unaliased components either.  This
makes the type conversion in the body of Pack3 illegal, which is the desired
behavior since otherwise the discriminant of an aliased component of My_Arr
would be modified.  Did I understand this correctly?

However, it seems that you can get around this by using generics, since by
12.5.3(8) and AARM 12.5.3(8.a) it's OK if a formal array type's components are
unaliased and the actual's are aliased, and Legality Rules such as 4.6(24.8)
aren't checked in an instance body.

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

Questions? Ask the ACAA Technical Agent