Version 1.10 of ai05s/ai05-0019-1.txt

Unformatted version of ai05s/ai05-0019-1.txt version 1.10
Other versions for file ai05s/ai05-0019-1.txt

!standard 13.14(2)          07-10-01 AI05-0019-1/04
!standard 13.14(3/1)
!standard 13.14(8.1/1)
!standard 13.14(10)
!standard 13.14(14)
!standard 13.14(15.1/2)
!class binding interpretation 06-11-10
!status Amendment 201Z 08-11-26
!status WG9 Approved 07-11-08
!status ARG Approved 7-0-3 07-06-03
!status work item 06-11-10
!status received 06-11-09
!priority High
!difficulty Hard
!qualifier Error
!subject Primitive subprograms are frozen with a tagged type
!summary
The types of tagged parameters are not frozen when the subprogram is frozen.
!question
RM-13.14(15.1/2) says:
At the place where a specific tagged type is frozen, the primitive subprograms of the type are frozen.
This seems like a hugely incompatible change, and in fact it breaks a lot of existing code.
Here's an example. We have two tagged private types. Freezing T2 causes Primitive to be frozen (by AI95-00341). That causes its parameter types to be frozen, which freezes T1'Class, which freezes T1, which is illegal, because T1 is not fully defined.
package P is type T1 is tagged private; type T2 is tagged private;
procedure Primitive (X : T1'Class; Y : T2);
private type T2 is tagged null record; Object : T2; -- Freeze T2 here. type T1 is tagged null record; end P;
Is this intended? (No.)
!recommendation
(See Summary.)
!wording
Add after 13.14(2):
This clause also defines a place in the program text where the profile of each declared callable entity becomes "frozen". A use of a callable entity causes freezing of its profile in some contexts, as described below. At the place where the profile of a callable entity becomes frozen, the entity itself becomes frozen.
Change 13.14(3/1) as follows:
The end of a declarative_part, protected_body, or a declaration of a library package or generic library package, causes freezing of each entity {and profile} declared within it, except for incomplete types. A noninstance body other than a renames-as-body causes freezing of each entity {and profile} declared before it within the same declarative_part.
Change 13.14(8.1/1) as follows:
An implicit call freezes the same entities {and profiles} that would be frozen by an explicit call. This is true even if the implicit call is removed via implementation permissions.
Add after 13.14(10):
o At the place where a function call causes freezing, the profile of the function is
frozen. Furthermore, if a parameter of the call is defaulted, the default_expression for that parameter causes freezing.
AARM Note: This is the important rule: a call freezes the profile. Note that we don't need to consider procedure or entry calls, because the end of a declarative_part freezes everything. We are moving here the part about defaulted parameters in function calls: it used to be in 13.14(14), but that paragraph is now only concerned with profiles, not calls.
o At the place where a generic_instantiation causes freezing of a callable entity, the
profile of that entity is frozen.
AARM Note: The generic might call the actual for one of its formal subprograms, so we need to know the profile.
Change 13.14(14) as follows:
At the place where a [callable entity] {profile} is frozen, each subtype of [its] {the} profile is frozen. If the {corresponding} callable entity is a member of an entry family, the index subtype of the family is frozen. [At the place where a function call causes freezing, if a parameter of the call is defaulted, the default_expression for that parameter causes freezing.]
Change 13.14(15.1/2) as follows:
o At the place where a specific tagged type is frozen, the primitive subprograms
of the type are frozen. {At the place where a type is frozen, any subprogram named in an attribute_definition_clause for the type is frozen.}
AARM Note: The second sentence is the rule that makes it possible to check 13.3(6) without going through hoops.
!discussion
Here's another example of the problem with the original rule:
package P is type T1 is tagged private; type T2 is tagged private; type Parent is tagged null record;
procedure Primitive (X : T1'Class; Y : T2'Class; Z : Parent);
private type T1 is new Parent with null record; -- Freeze Parent here. type T2 is tagged null record; end P;
Some rule is needed to avoid problems with the convention of inherited routines (see 3.9.2(10/2)). Without some rule, the convention of a primitive routine can be changed after it is inherited.
Similarly, it was always the intent of Ada that the tag could be built when the type is frozen. The primitive subprograms need to be frozen for that to be possible.
OTOH, the level of incompatibility incurred was unanticipated by AI95-00341. Thus, some adjustment to the rule is needed.
Another problem that came up in the discussion is this: 13.3(6) says that a subprogram used in an attribute_definition_clause must have convention Ada. This is nasty because the subprogram may only be frozen after the type to which the attribute_definition_clause is applied:
type My_Int is range 0 .. 100;
procedure Bad_Output (Stream : not null access Ada.Streams.Root_Stream_Type'Class; A : in My_Int'Base);
for My_Int'Output use Bad_Output;
X : My_Int; pragma Convention (C, Bad_Output); -- Wrong convention, but too late...
It seems that this example is somewhat related to the one in AI95-00341: a type gets frozen before everything is known about its "important" subprograms.
The solution is to separate the freezing of a callable entity from that of its profile. When a subprogram is frozen, it is not possible to give representation items for it. Therefore, the pragma Convention in the example above is illegal, because the declaration of X freezes My_Int which freezes Bad_Output. Similarly, in the example of AI95-00341, the address clause is illegal because the declaration of X freezes Ctrl which freezes Finalize.
Thus, the freezing rules ensure that at the (first) freezing point for a type the compiler knows enough about the "important" subprograms to be able to generate the dispatch table and other type-specific data structures. It can also perform all the necessary legality checks regarding these subprograms.
Still, freezing a subprogram does not (necessarily) freezes its profile. The reason is that the profile needs only be frozen when the compiler needs to generate code for a call (at which point it must know the sizes, passing conventions, etc. for the parameters). So the only constructs that need to freeze a profile are those that can call the subprogram: this includes (function) calls, generic instantiations, bodies, the end of declarative parts, and the end of compilation units.
If we look at the example in the !question, we see that the declaration of Object freezes T2, which freezes the subprogram Primitive, but not its profile. Therefore, T1 is not frozen (yet), and the source code is legal. T1 (and the profile of Primitive) will only be frozen at the end of the compilation unit.
!corrigendum 13.14(2)
Insert after the paragraph:
The freezing of an entity occurs at one or more places (freezing points) in the program text where the representation for the entity has to be fully determined. Each entity is frozen from its first freezing point to the end of the program text (given the ordering of compilation units defined in 10.1.4).
the new paragraph:
This clause also defines a place in the program text where the profile of each declared callable entity becomes frozen. A use of a callable entity causes freezing of its profile in some contexts, as described below. At the place where the profile of a callable entity becomes frozen, the entity itself becomes frozen.
!corrigendum 13.14(3/1)
Replace the paragraph:
The end of a declarative_part, protected_body, or a declaration of a library package or generic library package, causes freezing of each entity declared within it, except for incomplete types. A noninstance body other than a renames-as-body causes freezing of each entity declared before it within the same declarative_part.
by:
The end of a declarative_part, protected_body, or a declaration of a library package or generic library package, causes freezing of each entity and profile declared within it, except for incomplete types. A noninstance body other than a renames-as-body causes freezing of each entity and profile declared before it within the same declarative_part.
!corrigendum 13.14(8.1/1)
Replace the paragraph:
An implicit call freezes the same entities that would be frozen by an explicit call. This is true even if the implicit call is removed via implementation permissions.
by:
An implicit call freezes the same entities and profiles that would be frozen by an explicit call. This is true even if the implicit call is removed via implementation permissions.
!corrigendum 13.14(10)
Insert after the paragraph:
the new paragraphs:
!corrigendum 13.14(14)
Replace the paragraph:
At the place where a callable entity is frozen, each subtype of its profile is frozen. If the callable entity is a member of an entry family, the index subtype of the family is frozen. At the place where a function call causes freezing, if a parameter of the call is defaulted, the default_expression for that parameter causes freezing.
by:
At the place where a profile is frozen, each subtype of the profile is frozen. If the corresponding callable entity is a member of an entry family, the index subtype of the family is frozen.
!corrigendum 13.14(15.1/2)
Replace the paragraph:
At the place where a specific tagged type is frozen, the primitive subprograms of the type are frozen.
by:
At the place where a specific tagged type is frozen, the primitive subprograms of the type are frozen. At the place where a type is frozen, any subprogram named in an attribute_definition_clause for the type is frozen.
!ACATS test
Make a C-Test that is similar to the example, and possibly B-Tests for any remaning incompatibilities.
!appendix

From: Robert A. Duff
Date: Friday, November 10, 2006 11:13 AM

RM-13.14(15.1/2) says:

15.1/2 {AI95-00341-01} At the place where a specific tagged type is frozen,
      the primitive subprograms of the type are frozen.

This seems like a hugely incompatible change, and in fact it breaks a lot of
AdaCore's customer's code.  Am I misinterpreting this rule?

If not, I presume this rule applies to Ada 95, since the AI is classified as a
binding interpretation.  Right?

Here's an example.  We have two tagged private types.  Freezing T2 causes
Primitive to be frozen (by AI95-00341).  That causes its parameter types to be
frozen, which freezes T1'Class, which freezes T1, which is illegal, because T1
is not fully defined.

    package P is
        type T1 is tagged private;
        type T2 is tagged private;

        procedure Primitive (X : T1'Class; Y : T2);

    private
        type T2 is tagged null record;
        Object : T2; -- Freeze T2 here.
        type T1 is tagged null record;
    end P;

Here's another example:

    package P is
        type T1 is tagged private;
        type T2 is tagged private;
        type Parent is tagged null record;

        procedure Primitive (X : T1'Class; Y : T2; Z : Parent);

    private
        type T1 is new Parent tagged null record; -- Freeze Parent here.
        type T2 is with null record;
    end P;

It is clear from the AI that this was not intended.  For example, it says,
"It is not legal to declare any additional operations after the freezing of the
type anyway, so this change will not have any effect on what can be declared."
And the "!ACATS test" section worries about how to construct a portable address
clause, which is a pretty obscure issue.

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

From: Robert Dewar
Date: Friday, November 10, 2006 11:31 AM

> This seems like a hugely incompatible change, and in fact it breaks a lot of
> AdaCore's customer's code.  Am I misinterpreting this rule?

Note: it does seem to be needed if you want to statically build the
dispatch table at the point of freezing. We just installed new code
to do just that, which depends on the above rule, so that's how we
ran into a bunch of incompatibilities (CLAW is by the way one of the
programs that bumps into this :-))
> 
> If not, I presume this rule applies to Ada 95, since the AI is classified as a
> binding interpretation.  Right?

I definitely think that if we decide to keep this rule, we should hold
our noses and say it applies to Ada 95, and that we intended this all
along.

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

From: Robert A. Duff
Date: Friday, November 10, 2006 11:37 AM

>...(CLAW is by the way one of the
> programs that bumps into this :-))

And SofCheck Inspector is another one.  ;-)

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

From: Tucker Taft
Date: Friday, November 10, 2006 11:45 AM

I think it is intended to apply to Ada 95.  There is
nothing about it that is specific to Ada 2005 features.
It seems like a reasonable rule as well.  Certainly the
example you give below can easily be adjusted to accommodate
the rule.  I can imagine more complicated situations
might exist, of course.

The freezing rules have always been a bit difficult in the
area of tagged type primitives, such as the rule requiring
no additional primitives after a type derivation.  This makes them a bit
more so, but I think there are good reasons behind the
rules.

So I think the customers will have to adjust to the new rule.
I don't see the rule being eliminated or reinterpreted.

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

From: Robert Dewar
Date: Friday, November 10, 2006 11:35 AM

> I definitely think that if we decide to keep this rule, we should hold
> our noses and say it applies to Ada 95, and that we intended this all
> along.

Note that I am equally happy with dumping the rule (it would cause us to
go back and rethink how to build dispatch tables, but that's not so
terrible).

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

From: Randy Brukardt
Date: Friday, November 10, 2006  12:08 PM

> This seems like a hugely incompatible change, and in fact it breaks a lot of
> AdaCore's customer's code.  Am I misinterpreting this rule?

I doubt it. It was always intended that it be possible to build tags at the
freezing point, and we need to ban rep. clauses (specifically pragma
Convention) from happening after that point.

> If not, I presume this rule applies to Ada 95, since the AI is classified as a
> binding interpretation.  Right?

Correct.

> Here's an example.  We have two tagged private types.  Freezing T2 causes
> Primitive to be frozen (by AI95-00341).  That causes its parameter types to be
> frozen, which freezes T1'Class, which freezes T1, which is illegal, because T1
> is not fully defined.

I don't think we thought about the freezing of parameters that is a
side-effect of this rule.

One could try to patch up these examples by saying that class-wide
parameters aren't frozen when the subprogram is (they're pass by reference,
so we don't need to know anything about them to generate calls -- a fact
that limited views depend heavily on; and the occurrence of the body will
freeze them before any dispatching call could be made). A similar exception
could be made for access-to-class-wide.

But that seems like a fairly weird exception to the rules, and undoubtedly
there are examples that don't depend on class-wide types. I'm not sure if it
is worth it (not having seen how CLAW has problems with this new rule... ;-)

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

From: Tucker Taft
Date: Friday, November 10, 2006  2:11 PM

Given that we allow incomplete tagged types as parameters,
it seems like we could easily (and probably should) allow a
special case for tagged type parameters in the freezing rules.
That is, when a subprogram is frozen, the return subtype and the
non-tagged parameter subtypes are frozen, but not
the tagged parameter subtypes.  This would presumably
relieve some of the incompatibility pain.

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

From: Randy Brukardt
Date: Friday, November 10, 2006  2:36 PM

Yes, that would be fine for the primitive subprogram freezing (because the
controlling operands would necessarily be frozen). But I think it might
cause a problem with dispatching calls in other cases (not completely sure
though, because I can't off hand think of a way to get access to an unfrozen
object. We can dereference incomplete types, but other rules make
dispatching calls from such objects impossible.) After all, the call freezes
the subprogram, but if freezing the subprogram doesn't freeze the
parameters, things could get sticky.

We should certainly check this idea out more carefully, because freezing
unrelated class-wide types that happen to be used as parameters in primitive
operations is unpleasant. (I don't relish trying to restructure Claw -- it
was hard enough to structure as it is.)

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

From: Robert A. Duff
Date: Friday, November 10, 2006  2:27 PM

> I think it is intended to apply to Ada 95.

OK, good, at least we agree on that point.

> The freezing rules have always been a bit difficult in the
> area of tagged type primitives, such as the rule requiring
> no additional primitives after a type derivation.  This makes them a bit
> more so, but I think there are good reasons behind the
> rules.

There may be good reasons behind the freezing rules in general.  I think
everyone interested in this topic should go back and read the AI, including the
appendix.  It will become clear that for THIS particular rule, the reasons are
rather weak.  It comes across as an offhand conversation between Randy and Tuck
-- Should we do this?  Sure, what the heck, why not?  The AI talks about
obscure stuff like address clauses and pragmas import on primitive ops of a
tagged type.  It's clear that the wider ramifications -- incompatibility --
were not considered at all.

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

From: Robert A. Duff
Date: Friday, November 10, 2006  2:40 PM

> I doubt it. It was always intended that it be possible to build tags at the
> freezing point, and we need to ban rep. clauses (specifically pragma
> Convention) from happening after that point.

Yes, it was intended, and this rule should have been there from the start.  But
it wasn't, so we have a compatibility problem, and AdaCore has proof in our
bug-report database that this is a problem in practise.

I have no problem with banning Convention and Address clauses after that point,
which is all the AI talks about.  I think this is a simple case where ARG
didn't realize the compatibility issue.  Note that the AI has some handwringing
about how it will be difficult to even construct an ACATS test that
deliberately violates the rule!

I would tolerate the incompatibility if there were some practical benefit, but
here, we're just trying to obey a language design principle for no concrete
reason.  I think we should look for a narrow rule that worries specifically
about Convention/Address.  Randy and Tucker have made some suggestions, but I
don't fully understand the ramifications.

If we can't build dispatching tables at the freezing point of the type, then
too bad, we'll have to build them at the latest of the freezing point of the
type and freezing points of the primitives.  A little sad, but hardly worth
this incompatibility.

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

From: Robert Dewar
Date: Friday, November 10, 2006  3:08 PM

> If we can't build dispatching tables at the freezing point of the type, then
> too bad, we'll have to build them at the latest of the freezing point of the
> type and freezing points of the primitives.  A little sad, but hardly worth
> this incompatibility.

More than a little sad, means throwing away a months work and missing 
the release on the static dispatch tables, oh well :-(

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

From: Tucker Taft
Date: Friday, November 10, 2006  4:43 PM

> Yes, that would be fine for the primitive subprogram freezing (because the
> controlling operands would necessarily be frozen). But I think it might
> cause a problem with dispatching calls in other cases (not completely sure
> though, because I can't off hand think of a way to get access to an unfrozen
> object. We can dereference incomplete types, but other rules make
> dispatching calls from such objects impossible.) After all, the call freezes
> the subprogram, but if freezing the subprogram doesn't freeze the
> parameters, things could get sticky.

I don't see why, if we are only talking tagged types.  Presumably the
actual parameter must be an object of the formal parameter type or
a derivative of it, so clearly by then the formal parameter will have
been frozen.  I don't think dispatching makes it any harder at the
point of the call.
> 
> We should certainly check this idea out more carefully, because freezing
> unrelated class-wide types that happen to be used as parameters in primitive
> operations is unpleasant. (I don't relish trying to restructure Claw -- it
> was hard enough to structure as it is.)

Bob and Robert haven't commented on the above suggestion.
I'm curious whether it would resolve Bob's upward compatibility
concerns.

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

From: Randy Brukardt
Date: Friday, November 10, 2006  5:24 PM

> Bob and Robert haven't commented on the above suggestion.
> I'm curious whether it would resolve Bob's upward compatibility
> concerns.

Well, Bob in fact did, an hour ago: "Randy and Tucker have made some
suggestions, but I
don't fully understand the ramifications." Moreover, I think his mail
indicates that he'd just as soon we repeal the rule altogether and give up
on the static tag model. (He believes the incompatibility is too great to be
justified for this corner case.) Robert's messages seemed more sympathetic
to keeping the rule (possibly with tweaks).

I surely don't want to claim to understand all of the ramifications either,
but here are some:

(1) Without the rule, we allow "late" use of pragma Convention. That would
make the rules about inherited conventions into a total mess. See
6.3.1(13.2/1) and 3.9.2(10/2). That's because the convention of a primitive
could change after it was inherited (assuming that freezing of the parent
type didn't freeze primitives). Yes, this isn't very likely in practice, but
it's an ugly case that needs to be addressed.

(2) The change proposed by Tucker surely eliminates any incompatibility in
the examples given by Bob (in both cases, the problem parameter was a
class-wide one, which certainly is tagged).

(3) Examples with incompatibilities would surely continue to exist (you can
write similar cases class-wide function results, and with untagged types). I
think these are much less likely to occur in practice, and the untagged ones
would be easier to work around in practice (elementary types cannot depend
on the tagged ones, so they can be moved easily; records could be converted
to tagged types if they couldn't be moved). But almost certainly, we've need
to find out if real-world code still has problems, and that could only be
done with a sample implementation.

(4) The proposed change is safe in all cases except (possibly) dispatching
calls. That's because we already allow incomplete tagged views to be
parameters; they have even less information than an unfrozen tagged type. If
a compiler can handle the first, it surely can handle the latter. So the
change would be reasonably safe; it could be completely safe by saying that
it only applies to non-controlling tagged parameters. (That would have no
effect on the compatibility issue, as the type that the operation is
primitive for is already being frozen, and no other type also could be
controlling as that would violate the only one controlling type rule. But of
course the rule would be more complex.)

Because of (1), just reverting to the Ada 95 rule really doesn't work. (It
didn't work in Ada 95, either.) I suspect Bob would probably be happier if
we just fixed (1) by inventing a new kind of freezing for subprograms that
freezes the subprogram (thus preventing later rep. clauses) without freezing
the parameters. That would certainly solve the original problem, but I
wonder about the ramifications of that -- would that really allow static tag
creation, or are the forms of the parameters needed for that? (I don't think
Janus/Ada needs to know the forms of the parameters to create a tag, but I
don't want to extrapolate.)

I would like to find out if Tucker's change actually reduced the
incompatibility to manageable levels, or if it really doesn't help. It's
hard to decide what to do without that information. But I think someone
would have to have a compiler implementing Tucker's proposal in order to see
what the effect was to get it: this is just too complicated to check by
hand. Perhaps that would be easy enough to implement in the development
version of GNAT that shows these incompatibilities -- if so, the information
would be greatly appreciated.

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

From: Edmond Schonberg
Date: Friday, November 10, 2006  5:49 PM

The concerns that Bob first voiced come from the implementation of  
the AI-341 rule in GNAT (part of a move to build static dispatch  
table). We found two dozen tests in our regression suite that were  
now rejected. We are checking that those rejections are correct, i.e.  
that our implementation is not crying wolf unnecessarily. Most of the  
cases I have seen involve a class-wide parameter, so it is very  
likely that Tucker's relaxed rule will fix those. However, it is  
really a pity to give up the possibility of building static dispatch  
tables, and for that the subprograms have to be frozen. We will  
report in a few days on whether the cases that are properly rejected  
are hard to fix, or require just moving some declaration further  
down, in which case we can tell users to adapt.

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

From: Robert A. Duff
Date: Saturday, November 11, 2006  7:58 AM

> Well, Bob in fact did, an hour ago: "Randy and Tucker have made some
> suggestions, but I
> don't fully understand the ramifications." Moreover, I think his mail
> indicates that he'd just as soon we repeal the rule altogether and give up
> on the static tag model.

No!  I definitely think the dispatch tables should be statically allocated and
statically initialized.  If the rule in question is necessary to make that
possible, then I think we should keep it.  (Or Tuck's suggestion, presuming
that's less incompatible.)  Why is it necessary?  I understand the Convention
and Address issues mentioned in the AI, but what else?

I'm curious as to what other compilers do with the examples I sent,
and whether they do in fact build static dispatch tables.

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

From: Robert Dewar
Date: Saturday, November 11, 2006  8:07 AM

We will try implementing the relaxation rule suggested and see how many
of the "incomaptibilities" this removes, and report back.

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

From: Tucker Taft
Date: Saturday, November 11, 2006  12:55 PM

We have always built static dispatch tables.  But we
don't actually use the "official" freezing point to
decide when to build them.  We build them as soon
as we know enough (at compile-time) to do so.  If that
happens after the "official" freezing point, it doesn't
really matter.  We assign the tables a "linkname" very
early in the process, so we can generate references
to the tables before we generate the tables themselves.

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

From: Randy Brukardt
Date: Monday, November 13, 2006  12:18 AM

Yes, that sounds about like what happens in Janus/Ada. We assign a
symbol at the point of the type declaration for the tag, and actually
build the tag at the end of the package or declarative part. (I know
we tried doing it at the freezing point, and it didn't work for some
reason, so we moved it.)

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

From: Pascal Leroy
Date: Monday, November 13, 2006  4:47 AM

> This seems like a hugely incompatible change...

I hate to say I told you so, but I told you so.  I was the lone "against"
vote when this AI was discussed in Palma, because I didn't buy the
argument that "you just move the pragma around".  Messing with the
freezing rules made me extremely uncomfortable, but unfortunately this AI
was only discussed at this one meeting, so I didn't have time to look for
a compelling example that would have killed the proposal.

Now one thing that I didn't realize is that, being a binding
interpretation, it applies to Ada 95.  It would have been bad enough to
ask customers to restructure their code when migrating to Ada 2005, but
forcing them to do that in Ada 95 is intolerable.

I am all in favor of maintaining the invariant that dispatching tables may
be laid out when the type is frozen, but the problem described by the AI
was a relatively obscure wart, and we fixed it by doing open-heart
surgery.  And now that open-heart surgery failed we are going to do a
heart-lung transplant by completely changing the way that tagged types get
frozen.

Changing the freezing rules should only be done with the utmost care.  One
reason is that it's really hard to work out all their consequences.
Another reason is that they are really hard to implement, and that since
(some) compilers make many decisions at the freezing point, any change can
be very destabilizing for implementations.  Finally, these rules are
rather incomprehensible to users, so it's actively harmful to make them
more complicated than they already are.

Incidentally, I implemented this AI fairly recently (for Ada 2005 only),
and was very surprised to see that it led to incompatibilities in our own
code.  Only a very small number of the Amendment changes have had that
effect.  I am not aware of problems in our regression tests, but that must
be because the change has not percolated far enough yet: I am sure that
Claw is one of our tests.  At any rate, I am *not* going to apply this
change to Ada 95, regardless of what the ARG decides: I don't particular
want to p*ss off customers.

Since the problem is relatively marginal, we should  fix it by a small
tweaking of the rules, and drop AI 341.  I believe that something like the
following would work:

"A representation_item for a primitive subprogram of a tagged type shall
appear before the type is frozen."

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

From: Dan Eilers
Date: Monday, November 13, 2006  7:52 PM

> I'm not sure if it is worth it (not having seen how CLAW has problems
> with this new rule... ;-)

The problem is with type Root_Control_Type in Claw.ads.

Adam has come up with an example where rearranging the code
is not feasible:

   package P is
        type T1 is tagged private;
        type T2 is tagged private;
        procedure Primitive (X : T1'Class; Y : T2);
    private
        type T2 is tagged null record;
        type T2_Acc is access all T2;
        Object : aliased T2; -- Freeze T2 here.
        type T1 is tagged record
           F1 : T2_Acc := Object'Access;
        end record;
    end P;


Pascal wrote:
> Since the problem is relatively marginal, we should  fix it by a small
> tweaking of the rules, and drop AI 341.  I believe that something like the
> following would work:
>
> "A representation_item for a primitive subprogram of a tagged type shall
> appear before the type is frozen."

This sounds good.

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

From: Robert Dewar
Date: Monday, November 13, 2006  9:30 PM

> I hate to say I told you so, but I told you so.  I was the lone "against"
> vote when this AI was discussed in Palma, because I didn't buy the
> argument that "you just move the pragma around".  Messing with the
> freezing rules made me extremely uncomfortable, but unfortunately this AI
> was only discussed at this one meeting, so I didn't have time to look for
> a compelling example that would have killed the proposal.
> 
> Now one thing that I didn't realize is that, being a binding
> interpretation, it applies to Ada 95.  It would have been bad enough to
> ask customers to restructure their code when migrating to Ada 2005, but
> forcing them to do that in Ada 95 is intolerable.

Before we move too fast on this, let's complete our study of whether
introducing the relaxation of the rule that was suggested preserves
the behavior we want without introducing too much incompatibility.
First looks in our test suite indicate that all (yes, 100%) of the
compatibility issues disappear with this relaxation, so this may be
the answer. More details from Javier later

> I am all in favor of maintaining the invariant that dispatching tables may
> be laid out when the type is frozen, but the problem described by the AI
> was a relatively obscure wart, and we fixed it by doing open-heart
> surgery.  And now that open-heart surgery failed we are going to do a
> heart-lung transplant by completely changing the way that tagged types get
> frozen.
> 
> Changing the freezing rules should only be done with the utmost care.  One
> reason is that it's really hard to work out all their consequences.
> Another reason is that they are really hard to implement, and that since
> (some) compilers make many decisions at the freezing point, any change can
> be very destabilizing for implementations.  Finally, these rules are
> rather incomprehensible to users, so it's actively harmful to make them
> more complicated than they already are.
> 
> Incidentally, I implemented this AI fairly recently (for Ada 2005 only),
> and was very surprised to see that it led to incompatibilities in our own
> code.  Only a very small number of the Amendment changes have had that
> effect.  I am not aware of problems in our regression tests, but that must
> be because the change has not percolated far enough yet: I am sure that
> Claw is one of our tests.  At any rate, I am *not* going to apply this
> change to Ada 95, regardless of what the ARG decides: I don't particular
> want to p*ss off customers.

It would be nice if you would pass on this kind of surprise when it 
happens, or is this also IBM restricted information? :-)

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

From: Pascal Leroy
Date: Tuesday, November 14, 2006  1:48 AM

> Before we move too fast on this, let's complete our study of 
> whether introducing the relaxation of the rule that was 
> suggested preserves the behavior we want without introducing 
> too much incompatibility. First looks in our test suite 
> indicate that all (yes, 100%) of the compatibility issues 
> disappear with this relaxation, so this may be the answer. 
> More details from Javier later

Well, let's not ignore the fact that you might be lucky.  I found one
incompatibility in our implementation of the containers yesterday: the
full declaration for Empty_List freezes List, which freezes Cursor
(because of the numerous subprograms that take both a List and a Cursor),
and Cursor was not completely defined.  In this instance the fix was just
to move up the full declaration for Cursor, but as Adam's example
demonstrates, things can get ugly in other cases.

Since Cursor is untagged, the relaxation proposed by Tuck wouldn't help.

> It would be nice if you would pass on this kind of surprise when it 
> happens, or is this also IBM restricted information? :-)

I will, but that won't happen until I return from the ARG meeting.

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

From: Randy Brukardt
Date: Monday, January 15, 2007  8:00 PM

A summary of the minutes of 31st ARG meeting says:

The solution seems to be to partially freeze the subprogram when the
type is frozen. That is, freeze the subprogram but not the parameters.
Randy suggests that we might separate freezing the subprogram and
freezing the profile. (The profile would be frozen by calls, etc.)
13.14(14) says that the callable entity freezes its profile; we’d need
to break that. The profiles would have to be frozen at the end of the
unit (in the normal way). What bad would happen if we did that? No one
has any real problems.

Tucker suddenly announces that we don’t need any rules to freeze the profile:
he thinks the types will be frozen by a call or instantiation or default expression.

---

I don’t buy Tucker’s idea. I don’t see anything other than the first sentence
of 13.14(14) that would freeze the result of a function call. Yes, any program
with a problem would necessarily raise Program_Error, but that would violate
the meta-rule Bob described so eloquently:

"General principle: it's silly to require a compiler to deduce some fact, and
respond by generating code to raise an exception.  If we're going to require
such a deduction, the response should be a (legality) error message.  And it's
our duty to write down what needs to be deduced, rather than leaving it
implicit."

Consider a program like your example from that AI (AI05-0017-1):

	package Stt is 
	    type T is tagged private; 
	    function F return access T'Class; 
	    function G (X : access T) return Integer; 
	    I : Integer := G (F); 
	private
	    type T is tagged null record; 
	end Stt;

Surely we want the call of G(F) to freeze F and more importantly, the result
type of F. I don’t see anything other than 13.14(14) that has that effect. So,
Danger, Will Robinson. ;-)

I think my original idea of profile freezing would work. Indeed, it might in fact
only be necessary to define it for calls. That would seem to be less dangerous
anyway (why change what isn’t a problem?).

Pascal privately replied:

Last time I gave some thought to the matter, while shaving, I came to the
conclusion that we actually needed to freeze profiles. Tuck’s proposal would
bring us dangerously close to Ada 83’s forcing occurrences.

To which I reply:

Hope you were not shaving with a blade. It's dangerous to think about freezing
while shaving with a blade...could lose a nose or ear!

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


Questions? Ask the ACAA Technical Agent