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

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

!standard 12.5.1(5.1/3)          14-05-08 AI12-0036-1/03
!class binding interpretation 12-11-29
!status Corrigendum 2014 13-12-06
!status WG9 Approved 14-06-27
!status ARG Approved 9-0-2 13-11-16
!status work item 12-11-29
!status received 12-08-01
!priority Low
!difficulty Medium
!qualifier Omission
!subject The actual for an untagged formal derived type cannot be tagged
!summary
The actual for an untagged formal derived type cannot be a tagged type.
!question
Consider:
generic type T1 is private; type T2 is new T1; type T3 is new T1; package Pack1 is procedure Proc; end Pack1;
package body Pack1 is
V1 : T1; V2 : T2; V3 : T3;
procedure Proc is begin V2 := T2(V1); -- (A) V3 := T3(V2); -- (B) V1 := T1(V2); -- (C) end Proc;
end Pack1;
type Root is tagged null record; type Child1 is new Root with record ... end record; type Child2 is new Root with record ... end record;
package Inst is new Pack1 (T1 => Root, T2 => Child1, T3 => Child2);
Nothing in the Standard makes this illegal. But the conversions (A) and (B) clearly cannot be allowed, as they would leave the extension components uninitialized. Indeed, such conversions would be illegal if type T1 was a tagged private type (and the other types were type extensions). (Conversions like (C) are not a problem for this case.)
Some rule has to make this illegal, right? (Yes.)
!recommendation
(See summary.)
!wording
Modify 12.5.1(5.1/3):
The actual type for a formal derived type shall be a descendant of the ancestor type and every progenitor of the formal type. If the formal type is nonlimited, the actual type shall be nonlimited. {The actual type for a formal derived type shall be tagged if and only if the formal derived type is a private extension.} If the reserved word synchronized appears in the declaration of the formal derived type, the actual type shall be a synchronized tagged type.
!discussion
An alternative solution would be to adjust the type conversion rules to disallow converting the formal derived type to its ancestor type, if that type could be tagged (that is, is a formal private type or a formal derived type whose ancestor could be tagged).
We selected the simpler rule of disallowing the instantiation, as it seems less likely to cause compatibility problems. For instance, Ada doesn't have an "any scalar type" kind of generic formal; formal private types are often used for that purpose. In that case, conversions to the ancestor would be expected and likely, but the generic would not be intended to be instantiated with any composite type (like a tagged type). On the other hand, rejecting the instance is unlikely to be a problem, as most such cases will want to allow extension and thus will be using tagged private types as the ancestor. In addition, untagged formal derived types are rare, so compatibility issues are likely to be much rarer.
This solution is still incompatible, but only in cases where the formal derived type does not accurately describe the actual. As noted above, we believe such instances will be rare.
Note that the problem does not require the types to be declared in the same generic unit; the problem also appears in cases like:
generic type T1 is private; package Pack1 is generic type T2 is new T1; type T3 is new T1; package Inner_Generic is ... end Pack1;
or:
generic type T1 is private; package Pack1 is ... end Pack1;
generic type T2 is new T1; type T3 is new T1; package Pack1.Child is ... end Pack1.Child;
The matching rule works in these cases as well.
We make the rule symmetric as it is possible to match a formal private extension with a nontagged type:
generic type N is tagged private; type NC is new N with private; package GG is ... end GG;
package P is type T1 is private; private type T1 is tagged ... end P;
with P; package Q is type T2 is new P.T1; end Q;
with Q; package body P is package G is new GG (T1, T2); ... end P;
Here, T1 is tagged, but T2 is not tagged nor an extension. It's not clear that there is any semantic problem with allowing a case like this, but we're taking the safest option here.
!corrigendum 12.5.1(5.1/3)
Replace the paragraph:
The actual type for a formal derived type shall be a descendant of the ancestor type and every progenitor of the formal type. If the formal type is nonlimited, the actual type shall be nonlimited. If the reserved word synchronized appears in the declaration of the formal derived type, the actual type shall be a synchronized tagged type.
by:
The actual type for a formal derived type shall be a descendant of the ancestor type and every progenitor of the formal type. If the formal type is nonlimited, the actual type shall be nonlimited. The actual type for a formal derived type shall be tagged if and only if the formal derived type is a private extension. If the reserved word synchronized appears in the declaration of the formal derived type, the actual type shall be a synchronized tagged type.
!ASIS
No ASIS impact.
!ACATS test
An ACATS B-Test should be created to test these rules.
!appendix

!topic Problem with untagged generic formal derived types
!reference 4.6
!from Adam Beneschan 12-08-01
!discussion

This example is based on a comp.lang.ada post from Georg Bauhaus.

    generic
        type T1 is private;
        type T2 is new T1;
        type T3 is new T1;
    package Pack1 is
        procedure Proc;
    end Pack1;

    package body Pack1 is
        
        V1 : T1;
        V2 : T2;
        V3 : T3;

        procedure Proc is
        begin
            V2 := T2(V1);  -- (A)
            V3 := T3(V2);  -- (B)
            V1 := T1(V2);  -- (C)
        end Proc;

    end Pack1;

    type Root is tagged null record;
    type Child1 is new Root with record ... end record;
    type Child2 is new Root with record ... end record;

    package Inst is new Pack1 (T1 => Root, T2 => Child1, T3 => Child2);

I can't find a rule that makes the declaration or body of Pack1
illegal; and the instantiation Inst appears to meet all the
requirements.  However, the result is that the type conversions in (A)
and (B) in the instance body would be illegal conversions outside the
instance body; and I think we don't want them to be legal even in an
instance body since the result will be that the components specified
in the extension parts will not be set to anything.  I believe this is
a contract model violation.

My suggestion: change 4.6(21.1/2) from

The target type shall be untagged;

to 

The target type shall be untagged, and shall not be a descendant of a
generic formal derived type whose ultimate ancestor is a generic
formal type.

This would make the type conversions (A) and (B) illegal.  (Although
paragraph 4.6(21.1) would no longer apply to (C), (C) would still be
legal because it's also handled by 4.6(22).)

(Note that the generic formals involved don't have to be in the same
generic formal part; the problem is the same in cases like

    generic
        type T1 is private;
    package Pack1 is
        generic
            type T2 is new T1;
            type T3 is new T1;
        package Inner_Generic is ... 
    end Pack1;

or
    
    generic
        type T1 is private;
    package Pack1 is ...
    end Pack1;
    
    generic
        type T2 is new T1;
        type T3 is new T1;
    package Pack1.Child is ...
    end Pack1.Child;

and the proposed solution should also work.)
    
I think adding this rule is very unlikely to break any existing code
or cause problems.  In fact, I can't even think of a reason why one
would need to declare generic formal types as above and instantiate
the generic with *untagged* types; thus, usually, the formal types
should be declared as tagged private or as private extensions, which
would make (A) and (B) illegal under existing rules.  

I tried to think of other cases, besides type conversions, where
instantiating an untagged generic formal derived type with a tagged
actual could cause problems; but I couldn't think of any.  If there
are, an alternative would be to add a rule like

The actual for a generic formal untagged derived type may not be a
tagged type

somewhere in 12.5.1.

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

From: Tucker Taft
Sent: Wednesday, August 1, 2012  2:31 PM

> The actual for a generic formal untagged derived type may not be a 
> tagged type
>
> somewhere in 12.5.1.

This latter change seems like the most straightforward one (after the usual
"may not" -> "shall not" fix ;-).

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

Questions? Ask the ACAA Technical Agent