Version 1.4 of ais/ai-00255.txt

Unformatted version of ais/ai-00255.txt version 1.4
Other versions for file ais/ai-00255.txt

!standard 8.5.1 (05)          01-08-31 AI95-00255/02
!standard 12.4 (09)
!class binding interpretation 01-02-09
!status work item 01-02-09
!status received 01-02-09
!qualifier Omission
!priority Low
!difficulty Medium
!subject Object renaming of subcomponents of generic in out objects
!summary
The nominal subtype of a formal object of a composite type is unconstrained if the first subtype of the type is unconstrained.
!question
Consider the following code (from an Ada 83 ACATS test):
type Rec (D : Integer := 1) is record ... case D is when 1 => F4 : Integer range -10 .. 0; ... end case; end record;
subtype Subrec1 is Rec (1);
generic Sr1 : in out Subrec1; package Genpack is ... Sx4 : Integer renames Sr1.F4; -- Illegal? (Yes.)
In Ada 83, the line marked "Illegal" is clearly illegal by RM83 8.5(5). However, there doesn't seem to be a rule in Ada 95 that makes the above illegal.
Is the line marked "Illegal?" illegal? (Yes.)
!recommendation
(See summary.)
!wording
(See corrigendum.)
!discussion
There is no intent to change the Ada 83 rule here. The rule was necessary to avoid disappearing components. Consider the example again, assuming for a moment that the declaration of Sx4 is legal:
type Rec (D : Integer := 1) is record case D is when 1 => F4 : Integer range -10 .. 0; end case; end record;
subtype Subrec1 is Rec (1);
generic Sr1 : in out Subrec1; package Genpack is Sx4 : Integer renames Sr1.F4; end Genpack;
X : Rec; package Inst is new Genpack (X); X := (D => 2); -- What happened to Inst.Sx4?
The instantiation Inst is legal, because the constraints of the subtype mark appearing in the formal_object_declaration don't play a role in parameter matching (see RM95 12.4(12)). So even though the nominal subtype of Srl is constrained, in an instantiation the corresponding object may be unconstrained.
Moreover, the intent is that object renamings and generic in out objects are equivalent (see, for instance, AARM 12.4(1.b)).
The best fix to this problem is to define the nominal subtype of a formal in out object of a composite type to be unconstrained if the first subtype of the type is unconstrained. This change also fixes another, related problem, with the prefix of 'Access. Assume that the F4 component is aliased. Then,
generic Sr1 : in out Subrec1; package Genpack is type Acc_Int is access all Integer; P : Acc_Int; ... P := Sr1.F4'access; -- Illegal? (Yes.)
is a similar problem to the renames, and should have a similar resolution.
Note that making the nominal subtype unconstrained doesn't grant additional permissions, because the only rule that requires an unconstrained nominal subtype is RM95 8.5.1(5), and it doesn't apply here because formal objects are never aliased.
!corrigendum 12.04(09)
Replace the paragraph:
A formal_object_declaration declares a generic formal object. The default mode is in. For a formal object of mode in, the nominal subtype is the one denoted by the subtype_mark in the declaration of the formal. For a formal object of mode in out, its type is determined by the subtype_mark in the declaration; its nominal subtype is nonstatic, even if the subtype_mark denotes a static subtype.
by:
A formal_object_declaration declares a generic formal object. The default mode is in. For a formal object of mode in, the nominal subtype is the one denoted by the subtype_mark in the declaration of the formal. For a formal object of mode in out, its type is determined by the subtype_mark in the declaration; its nominal subtype is nonstatic, and, for a composite type, is unconstrained if the first subtype of its type is unconstrained, even if the subtype_mark denotes a constrained or static subtype.
!ACATS test
ACATS tests B85003A and B85003B test this case.
!appendix

From: Randy Brukardt
Sent: Friday, February 09, 2001 5:29 PM

A language problem was pointed out by an implementor; discussion by the Fast
Reaction Team has indicated that there is a (wording) problem that ought to
be resolved by the ARG.

An existing ACATS test (a so-called 'legacy' test, meaning that it was an
Ada 83 test) contains the following:

        type Rec (D : Integer := 1) is
            record
                ...
                case D is
                    when 1 =>
                        F4 : Integer range -10 .. 0;
                        ...
                end case;
            end record;

        subtype Subrec1 is Rec (1);
	  subtype Subrec2 is Rec (2);

        generic
            Sr1 : in out Subrec1;
        package Genpack is
            ...
            Sx4 : Integer renames Sr1.F4;     -- ERROR: COMPONENT OF
                                              --  VARIANT PART.

In Ada 83, the error clearly follows from RM83 8.5(5). However, there
doesn't seem to be a rule in Ada 95 that makes the above illegal. The phrase
".. or if the variable is a generic formal object (of mode in out)" from Ada
83 has disappeared in Ada 95 almost without a trace. Usually, such changes
are recorded in "wording changes from Ada 83", but no notation of a change
is made there.

AARM 8.5.1(5.c) says that "if [the renamed entity] is a formal object, then
the
assume-the-best or assume-the-worst rules are applied as appropriate". This
seems to imply an intentional language change. On closer inspection,
however, it becomes clear that this statement is meaningless: there isn't a
general assume-the-worst rule. Rather, if the properties of the formal are
not be believed in the body, there is supposed to be a specific rule to that
effect (and no such rule appears here).

Moreover, if there had been an intent to change this rule, it should have
been
documented as an extension (as programs that were illegal in Ada 83 now are
legal in Ada 95). But there is no such documentation.

All compilers which have passed the ACATS clearly are implementing this rule
(until now, there have been no complaints about this rule).

Given that generic in-out parameters are rare, no one on the Fast Reaction
Team really wanted this to be a language change.

A friendly reading of the RM seems to provide the answer we want.

What we need is for 8.5.1(5) to apply to the generic in out object. The
first sentence of 8.5.1(5) says:

   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 aliased.

So we need to determine the nominal subtype of a generic in out object.
Unfortunately, 12.4(9) merely says that the nominal subtype is non-static;
it doesn't say whether it
is constrained or unconstrained.

The design intent for Ada 95 is that generic in out parameters and object
renamings are equivalent (see 12.4(1.b)). Therefore, we can look at the
wording of 8.5.1(6) to answer the question: "any constraint implied by the
subtype_mark of the object_renaming_declaration is ignored". Using this
rule, we can conclude that the nominal subtype of a formal object of a
composite type is unconstrained if the first subtype of the type is
unconstrained.

If we do that, then 8.5.1(5) applies in the above case, and the indicated
line is illegal.

However, this conclusion requires several leaps-of-faith, and it clearly
would be better if the wording makes this clear.

Note that the logic used for this argument would seem to imply that the same
rules apply to regular object renames; I'm not certain that is what we want.

Consider:

     Obj : Subrec1;

     RenObj : Subrec2 renames Obj; -- OK, constraint is ignored.
     SX5 : Integer renames RenObj.F4; -- OK??

If we conclude that the nominal subtype of a formal object of a composite
type is unconstrained if the first subtype of the type is unconstrained, as
we did for generic in out object above, then SX5 is illegal because the
nominal subtype is unconstrained and indefinite. OTOH, if we use the actual
constraint (which is what 8.5.1(6) says before the "any constraint implied"
part), then SX5 is legal. Such a literal interpretation of 8.5.1(6) applied
to generic in outs would give us essentially assume-the-best for the specs,
and a hole for the bodies (since there would need to be an assume-the-worst
rule) -- and the original questioning program would be legal.

So (assuming that we don't want to make compilers change here, in an area of
little benefit to users), I don't think that the best fix is clear.
(Apologies to those FRT members whose arguments I butchered in the
condensation above. :-)

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

From: dewar@gnat.com
Sent: Saturday, February 10, 2001 11:35 AM

I must say, I find the whole nominal subtype concept to be a can of worms.
Too bad we cannot find some better way of describing things in general here,
although there are very mysterious language features, like

   x : aliased String := "hello";
   x : aliased String (1 .. 5) := "hello";

being different, that make things hard to describe cleanly, and even
worse, the fact that

   x : aliased String (1 .. 5);

may not do what you want, and the ONLY way to do what you want is to
introduce a rubbish unnecessary initialization.

Well, not particularly relevant to this case, but the whole business of
actual subtypes and nominal subtypes being different is a definite point
of complexity in the language, that really did not exist in this virulent
form in Ada 83 :-)

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

From: Tucker Taft
Sent: Saturday, February 10, 2001 10:06 AM

> Note that the logic used for this argument would seem to imply that the same
> rules apply to regular object renames; I'm not certain that is what we want.

It is clear that the nominal subtype of the view declared by an object
renaming is identical to that of the renamed object, and the particular subtype
specified in the object renaming is irrelevant.

>
> Consider:
>
>      Obj : Subrec1;
>
>      RenObj : Subrec2 renames Obj; -- OK, constraint is ignored.
>      SX5 : Integer renames RenObj.F4; -- OK??
>
> If we conclude that the nominal subtype of a formal object of a composite
> type is unconstrained if the first subtype of the type is unconstrained, as
> we did for generic in out object above, then SX5 is illegal because the
> nominal subtype is unconstrained and indefinite. OTOH, if we use the actual
> constraint (which is what 8.5.1(6) says before the "any constraint implied"
> part), then SX5 is legal.

8.5.1(6) is unambiguous.  The properties of the view declared by the
renaming are identical to the renamed object.

> ...  Such a literal interpretation of 8.5.1(6) applied
> to generic in outs would give us essentially assume-the-best for the specs, ...

I don't agree.  The tricky part about generics is that legality rules are
enforced twice on its spec, once when the generic is declared, and once when it
is instantiated. Clearly, when the generic is instantiated, the legality rules
should be enforced following the rules of object renaming, where the in out
formal has properties identical to those of the actual.  However, when the
generic is declared, we must come up with a nominal subtype for the generic
formal.  Given that any constraints on the generic formal are completely
irrelevant, it would be odd to use those for the nominal subtype.  The only two
reasonable possibilities are the first subtype of its type, or a special rule
which says this rule is unenforced for a generic formal in the spec, and the
recheck upon instantiation is relied upon to provide protection. That seems
like overkill, and definitely a change from Ada 83.  So the best compromise
seems to be to specify that the nominal subtype for a composite generic formal
in out object is the first subtype of its type.  I agree this is a bit of
"creative" reading, but it seems justifiable.  Some "clarifying" wording
added to 12.4(9) would be welcome.

> and a hole for the bodies (since there would need to be an assume-the-worst
> rule) -- and the original questioning program would be legal.
>
> So (assuming that we don't want to make compilers change here, in an area of
> little benefit to users), I don't think that the best fix is clear.

I think the simplest fix is to specify the nominal subtype of a composite
formal in out object to be the first subtype of its type.

> (Apologies to those FRT members whose arguments I butchered in the
> condensation above. :-)

I think you captured it admirably well...

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

From: Randy Brukardt
Sent: Saturday, February 10, 2001 10:44 PM

> I think the simplest fix is to specify the nominal subtype of
> a composite formal in out object to be the first subtype of its type.

It's not so clear to me.

Are we sure making this change (definition, whatever you call it) won't
break something else? Nominal subtypes occur in a bunch of places (there are
eight references in the index). (Of course, you might be able to argue that
it also would *fix* something else...)

I think that the simplest fix would be restore the Ada 83 rule. It has the
advantage of being 100% compatible with Ada 83. And it wouldn't cause any
"ripple" changes.

Tucker's fix might be better, but I think someone would need to carefully
look at the possible effects before leaping on this one.

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

From: Tucker Taft
Sent: Sunday, February 11, 2001 8:41 AM

The problem with just restoring the Ada 83 wording is that it still
begs the question of what is the nominal subtype of a composite
formal in out object.  If you look at 3.3(23) where nominal subtype
is first introduced, it says that the actual subtype can be *more*
restrictive than the nominal subtype of the view.  If we make the
nominal subtype the same as the specified subtype of the formal
in out object, then we can violate this fundamental rule about
the relationship between nominal subtypes and actual subtypes.

I would not object to adding back the Ada 83 restriction against
renaming discrim-dependent components of formal in out objects.  However,
I think we also should define the nominal subtype so that we know
it won't violate the fundamental relationship specified in 3.3(23).
Otherwise, it seems clear that there will be more surprises, not
less.  And of course, once we do specify the nominal subtype so
that it preserves the relationship between actual and nominal, there
is probably no *need* to restore the Ada 83 restriction.

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

From: Randy Brukardt
Sent: Monday, February 12, 2001 3:27 PM

Humm, I understand your thinking, but I still worry about causing
compatibility problems. By making changing the definiteness of some generic
in out objects, we could easily make something illegal that currently is
legal. Someone will have to inspect every use of "nominal subtype" in the RM
(to insure that no compatibility problems are introduced), before I think we
can make a change like this.

This, of course, is the normal trade-off between a "patch" and a proper fix.
I'm all for the proper fix -- but let's make sure that it doesn't cause
other problems.

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

From: Tucker Taft
Sent: Monday, February 12, 2001 10:37 PM

Here are the ones I found by searching the "new" RM.  The ones with "**" might
be relevant to formal in out object.

**3.3(23) -- "nominal subtype" introduced -- actual subtype can be more
restricted than nominal subtype.

**3.3(26) -- ... if nominal subtype is constrained then actual subtype
is constrained

**3.3(26.d) -- nominal subtype is what is known at compile-time; actual
subtype is "run-time" subtype

3.3.1(8) -- object declared with a given nominal subtype

3.3.1(9) -- if nominal subtype is unconstrained, then object is constrained by
its initial value if subtype is indefinite, or object is constant or aliased.
Otherwise, nominal and actual subtypes are the same.

3.3.1(10) -- nominal subtype determines implicit initial value if not
explicitly initialized

3.3.1(12) -- implicit value of component with default expression is value of
expression converted to nominal subtype

3.3.1(17) -- explicit initial expression is evaluated and converted to
nominal subtype of object

3.6(11) -- nominal subtype of aliased discriminated component shall be
constrained

3.6(20) -- component_definition defines nominal subtype of array components

3.8(14) --- component_definition defines nominal subtype of record component

3.10(9) -- if view declared by object_declaration is aliased, and nominal
subtype is unconstrained, then object is constrained by its initial value

**3.10.2(26) -- In X'Access, X must not be discrim-dependent component of
nominally unconstrained variable, unless is aliased or subtype is indefinite
(or equivalently, variable enclosing X must be constrained by its initial value
if nominally unconstrained).

**3.10.2(27/1) -- In X'Access of access type A with designated subtype D, if D
is untagged, then type of X shall be same as D, and D shall statically match
nominal subtype of X or D shall be discriminated and unconstrained.

**3.10.2(30) -- If nominal subtype of X does not statically match D, then it
shall be view converted to D.

4.1(9) -- Nominal subtype of dereference is designated subtype of access type

4.1.1(5) -- Nominal subtype of indexed_component is component subtype of
array type

4.3.3(11) -- For an explicit_actual_parameter, an
explicit_generic_actual_parameter, the expression of a return_statement, the
initialization expression in an object_declaration, or a default_expression
[(for a parameter or a component)], when the nominal subtype of the
corresponding formal parameter, generic formal parameter, function result,
object, or component is a constrained array subtype, the applicable index
constraint is the constraint of the subtype

4.3.3(14) -- For a component expression in an aggregate, if the component's
nominal subtype is a constrained array subtype, the applicable index constraint
is the constraint of the subtype;

4.6(27) -- nominal subtype of conversion is target subtype

4.9(24) -- static constant must have static nominal subtype

** 4.9(32) -- object is statically constrained if nominal subtype is statically
constrained

5.4(7) -- if case expression is name with static and constrained nominal
subtype, then only values of that nominal subtype shall be covered

6.1(23) -- nominal subtype of formal parameter is subtype specified in
formal param spec

6.4(12) -- nominal subtype of call is result subtype

6.4.1(10,11,15) -- actual parameter converted to nominal subtype of formal

**6.4.1(16) -- formal param of mode in out or out is constrained if either
nominal subtype or actual's subtype is constrained

**8.5.1(5/1) -- object being renamed shall not be component of variable whose
nominal subtype is unconstrained, unless is indefinite or aliased (i.e.,
enclosing variable must be constrained by its initial value)... 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.

**12.4(9) -- For a formal object of mode in, the nominal subtype is the one
denoted by the subtype_mark in the declaration of the formal. {static (subtype)
[partial]} For a formal object of mode in out, its type is determined by the
subtype_mark in the declaration; its nominal subtype is nonstatic, even if the
subtype_mark denotes a static subtype.

12.4(11) -- Actual parameter converted to nominal subtype of
formal in object.

** analogous problem **12.6(9) -- the nominal subtypes of the formal parameters
and result, if any, are defined to be nonstatic, and unconstrained if of an
array type [(no applicable index constraint is provided in a call on a formal
subprogram)].

13.14(11) -- at the place where an object name causes freezing, the
nominal subtype associated with the name is frozen.

13.14(11/1) -- At the place where an implicit_dereference causes
freezing, the nominal subtype associated with the
implicit_dereference is frozen.


--------

That's it.  Note the analogous situation with formal subprograms, where
we define the nominal subtype of the parameter to be unconstrained.
It might have made more sense to define it to be constrained if and only if
the first subtype of the array type is constrained.

> This, of course, is the normal trade-off between a "patch" and a proper fix.
> I'm all for the proper fix -- but let's make sure that it doesn't cause
> other problems.

All the data we need are presumably in the above citations.  The interesting
cases are probably renaming and X'Access.  They seem to confirm the
need to define what is the nominal subtype, and the importance that it
not be constrained when the actual subtype might be unconstrained.

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

From: Randy Brukardt
Sent: Tuesday, February 13, 2001 3:25 PM

> Note the analogous situation with formal subprograms, where
> we define the nominal subtype of the parameter to be unconstrained.
> It might have made more sense to define it to be constrained if and only if
> the first subtype of the array type is constrained.

Yes, but I doubt that we could change that now.

> > This, of course, is the normal trade-off between a "patch" and a proper fix.
> > I'm all for the proper fix -- but let's make sure that it doesn't cause
> > other problems.
>
> All the data we need are presumably in the above citations. The interesting
> cases are probably renaming and X'Access.  They seem to confirm the
> need to define what is the nominal subtype, and the importance that it
> not be constrained when the actual subtype might be unconstrained.

Well, I find the data convincing. But I am a bit uncomfortable adopting a
different rule for generic in outs than for formal parameters; that's likely to
be confusing. (Of course, defining the nominal subtype to "universal no type"
would be the best solution, and I doubt that more than a handful of Ada users
would care.) Since this feature is so rarely used, we probably shouldn't get
too concerned about that.

I've slightly changed the AI to make the change Tucker suggests.

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

!topic Nominal subtype of IN OUT generic formal objects
!reference RM95-12.4(9), 8.5.1(5)
!from Adam Beneschan 03-01-02
!discussion

I believe that the language in 12.4(9) needs clarification.  I had a
lot of trouble figuring out whether this should be legal:

    type Rec (D : Integer := 1) is record
       case D is
          when 1 =>
             F1 : Integer;
          when others =>
             null;
       end case;

   subtype Rec1 is Rec(1);

   generic
      Obj1 : in out Rec1;
   package Genpack is
      Renames1 : Integer renames Obj1.F1;  -- LEGAL?
   end Genpack;

According to 8.5.1(5), the legality of the object rename depends on
whether the nominal subtype of Obj1 is unconstrained.  I tried to look
up the definition of a nominal subtype for a generic formal object in
12.4(9).  This paragraph reads:

    A formal_object_declaration declares a generic formal object.  The
    default mode is in.  For a formal object of mode in, the nominal
    subtype is the one denoted by the subtype_mark in the declaration
    of the formal.  For a formal object of mode in out, its type is
    determined by the subtype_mark in the declaration; its nominal
    subtype is nonstatic, even if the subtype_mark denotes a static
    subtype.

This tells me that for a generic formal IN OUT object, the nominal
subtype of the object is "nonstatic" (a property which does not help
determine whether the rename is legal), but it doesn't say what the
nominal subtype *is*.  From looking at the rest of the paragraph, I
concluded that the nominal subtype was the one denoted by the
subtype_mark, just as for IN objects, except that it was nonstatic.
This led me to believe that the renaming was legal, since the nominal
subtype of Obj1 would then be constrained, and 8.5.1(5) would not
apply.  However, the ACATS tests b85003a and b85003b contradicted this
conclusion.

I now have figured out, from 12.4(12), that the constraints on the
subtype are irrelevant and therefore the nominal subtype of Obj1
should be the first subtype of the object's type---but this is still
an assumption, more or less, since the RM doesn't really say that.  My
suggestion is to add language to 12.4(9) stating that the nominal
subtype of a generic formal IN OUT object is the first subtype, if
that is correct.

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

From:
Sent: Friday, March 1, 2002 9:26 PM

So did the ARG. :-) This looks almost exactly like the question in AI-255.
That AI is ready to be discussed at a meeting, but has been omitted from the
agenda (probably by mistake).

For future reference, there is a cross reference listing of AIs by paragraph
number on the web site, get to it from the HTML index:
   www.ada-auth.org/AI-SUMMARY.HTML
or directly at:
   www.ada-auth.org/AI-XREF.HTML

In this case, if you look at either 8.5.1 or 12.4, you'll find AI-255.

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

Questions? Ask the ACAA Technical Agent