Version 1.4 of 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); --
V3 := T3(V2); --
V1 := T1(V2); --
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