Version 1.12 of ai12s/ai12-0155-1.txt

Unformatted version of ai12s/ai12-0155-1.txt version 1.12
Other versions for file ai12s/ai12-0155-1.txt

!standard 3.10.1(10/3)          15-07-30 AI12-0155-1/08
!standard 13.14(3/4)
!standard 13.14(15.1/3)
!class binding interpretation 15-02-20
!status Amendment 1-2012 16-02-29
!status WG9 Approved 15-10-16
!status ARG Approved 6-0-3 15-06-26
!status work item 15-02-20
!status received 15-02-20
!priority Low
!difficulty Easy
!qualifier Omission
!subject Freezing of an incomplete view has no effect
!summary
Freezing of an incomplete view of a type has no effect. In particular, it does not freeze the completion of the view.
!question
Consider:
package Pack is
type Bag_Type is private;
procedure Add (Bag : in out Bag_Type; Elem : Integer);
private
type Set is tagged;
type Bag_Type is access Set;
package Inner is -- These can't be primitive for Set, else 3.10.1(9.3/2) is violated. procedure Add (Elem : Integer; To_Set : in out Set); procedure Union (Left, Right : in Set; Result : out Set); procedure Intersection (Left, Right : Set; Result : out Set); function "=" (Left, Right : Set) return Boolean; end Inner;
end Pack; -- Freezing here.
13.14(3/4) [and earlier versions as well] says that everything excepting incomplete types are frozen at the end of Pack. This includes the profiles of any subprograms declared within Pack.
13.14(14/3) tells us that freezing of a profile freezes each subtype of the profile. That means, for example, that freezing the profile of Union freezes Set.
But freezing of Set is illegal by 13.14(17/3) [the type is not yet complete]. [This is why there is an exception for incomplete types in 13.14(3/4), otherwise any incomplete type with the completion deferred to a body would be illegal.] Thus all of the declarations in package Inner are illegal.
The changes to the usage of incomplete types in Ada 2012 (AI05-0151-1) would suggest that these subprograms should be legal. They could be called from a child unit without that child having to see the full type for Set, so they seem potentially useful. Should such subprograms be allowed? (Yes.)
!recommendation
(See Summary.)
!wording
Add after 3.10.1(10/3):
The controlling operand or controlling result of a dispatching call shall not be of an incomplete view if the operand or result is dynamically tagged.
AARM Discussion: This rule is needed to prevent the following case:
package Pack is type T is tagged; function F return access T'Class; function G (X : access T) return Integer; I : Integer := G (F); -- Illegal by above rule. type T is tagged null record; end Pack;
If this was not illegal, the compiler would have to generate a dispatching call on G without necessarily knowing where the tag of type T is stored (the completion of T might not be until the body of Pack). The fact that any such call will raise Program_Error does not absolve us of detecting the problem; see the Language Design Principles in 13.14.)
[Editor's note: I made the rule as narrow as possible in order to avoid any compatibility issues. If the call to G had been statically tagged, there is no problem since the tag of the operand need not be read.]
Modify 13.14(3/4):
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 proper_body, body_stub, or entry_body causes freezing of each entity and profile declared before it within the same declarative_part[ that is not an incomplete type; it only causes freezing of an incomplete type if the body is within the immediate scope of the incomplete type].
Add after 13.14(15.1/3):
Notwithstanding the rest of this subclause, freezing an incomplete view has no effect.
AARM Ramification: In particular, freezing an incomplete view does not freeze the completion of the view. For an incomplete type, once the completion of the incomplete type is seen, any further references to the type will be of the complete type, which will be frozen in the normal way. Legality Rules prevent all problems for incomplete types themselves.
In constrast, freezing a partial view does have an effect (the completion of the view is frozen and the program is illegal if it hasn't occurred yet).
!discussion
13.14(3/4) has an explicit “hole” so that incomplete types whose completion is given in the body (so-called Taft-Amendment types) do not freeze. Otherwise, such incomplete types would be illegal as 13.14(17/3) would be violated when they were frozen at the end of the scope.
Ada 2012 added explicit rules allowing operations like the ones in the question. It seems bizarre that these operations are always illegal because of freezing; it reduces the value of the new rules.
Operations like the ones in the question can be useful to provide operations to child units of a subsystem on a Taft-Amendment type without having to make the full declaration visible.
Such operations are limited to non-primitive operations as any primitive operations of a Taft-Amendment type are illegal by 3.10.1(9.3/2). However, as noted in the question, it's easy to declare non-primitive operations by adding a nested package; this trick is widely known among expert Ada programmers, so it's likely to be used in this case.
----
In order to fix this hole, we could have made a bunch more exceptions as to where incomplete types are freezing. But that was getting more and more messy (changes to at least 13.14(3/4) and 13.14(10.2/3) would be required, and those are already messy).
13.14(1.j/3) suggests that we wanted to only use Legality Rules for incomplete types and not treat them as freezing. But that's not how 13.14 was worded (there is no exception for incomplete types). Moreover, there is one known case, discussed in AI05-0017-1, where the Legality Rules are insufficient and freezing of incomplete types fixed any problems.
Therefore, we need to add a Legality Rule to 3.10.1 to cover the one known case. Once we have that, there is no need to ever freeze an incomplete view, and thus we add a rule to explicitly state that.
We simplify the wording of 13.14(3/4) to eliminate all mentions of incomplete types or views, as those are covered by the new notwithstanding rule. (The new notwithstanding rule also covers - at least - explicit uses as a name, and occurrences of incomplete views in profiles.)
13.14(5/3) and 13.14(10.2/4) still need their mentions of formal incomplete types, as those are mainly about not freezing private types when used as an actual, and not freezing the profile of an actual subprogram with private type parameters. The rules are not specifically about incomplete types.
!corrigendum 13.14(3/4)
Replace the paragraph:
by:
!ASIS
No ASIS effect.
!ACATS test
The problem was originally discovered in ACATS test CC51011, so some version of that test will test the fix. There also is the proposed test named C3A1005, a version of CC51011 without the generic units. If this AI is approved, that test can be issued (it tests some moderate priority 3.10.1 objectives that are currently on the testing list -- this AI would raise that priority somewhat).
!appendix

From: Randy Brukardt
Sent: Friday, February 28, 2015  5:52 PM

I have had a running conversation with an implementer over a series of tests,
which has led to a question that suggests that there might be a problem
(really an oversight) in the freezing rules. (Imagine that!)

Here's the important part of the example:

package Pack is

   type Bag_Type is private;

   procedure Add (Bag : in out Bag_Type; Elem : Integer);

private

   type Set is tagged;

   type Bag_Type is access Set;

   package Inner is
      -- These can't be primitive for Set, else 3.10.1(9.3/2) is violated.
      procedure Add (Elem : Integer; To_Set : in out Set);
      procedure Union (Left, Right : in Set; Result : out Set);
      procedure Intersection (Left, Right : Set; Result : out Set);
      function "=" (Left, Right : Set) return Boolean;
   end Inner;

end Pack; -- Freezing here.

The implementer's complaints led me to look at how this freezes.

13.14(3/4) [and earlier versions as well] says that everything except
incomplete types are frozen at the end of Pack. This includes the profiles of
any subprograms declared within Pack.

13.14(14/3) tells us that freezing of a profile freezes each subtype of the
profile. That means, for example, that freezing the profile of Union freezes
Set.

But freezing of Set is illegal by 13.14(17/3) [the type is not yet complete].
[This is why there is an exception for incomplete types in 13.14(3/4),
otherwise any Taft-Amendment type would be illegal.] Thus all of the
declarations in package Inner are illegal.


This only matters to Taft-Amendment types like Set in the example. For a type
that is completed in the package specification, 13.14(17/3) does not apply at
the end of the package, because the type is in fact complete. For an
incomplete view, one assumes that types that are imported were previously
frozen by the end of the compilation unit that contains them and thus don't
need any freezing. [BTW, I can't find any justification for this view in the
RM wording; it's something that I wish we'd fix because it comes up
periodically, but it also seems to fit the Dewar rule as no other
interpretation makes sense (at least to me). And since it fits the Duff rule
as well (no one would ever change behavior because of the fix), I've never
made an AI for it. Interestingly, I made this very same point in the e-mail
in AI12-0151-1 (June 6, 2009), so maybe it's mainly this case where it
matters. That e-mail specifically argued that there was no freezing problem
for incomplete views from limited withs for this sort of case, in response to
a question from Tucker. It must have satisified everyone, because no further
discussion occurred on that point.]


Note that there is no problem with these profiles freezing without knowing the
full type. We allow calls on similarly defined subprograms when the parameter
type is a tagged incomplete view defined by a limited with. The parameters
have to be passed by reference, and dispatching calls are prevented by
3.10.1(9.3/2) [primitives aren't allowed].

Such routines can be used in child packages without having to make the actual
implementation visible. That seems useful to me. (Maybe not useful enough to
bother changing the language, but certainly useful enough to disqualify this
case from the ARG gallery of pathologies, honoring Steve Baird. :-)


The freezing requirement here says that the expansions in usage of incomplete
types defined in Ada 2012 are completely unusable for Taft-Amendment types.
Any use of a Taft-Amendment incomplete type directly as a parameter or result
will necessarily result in a freezing violation. It's hard to believe we
intended that.

OTOH, AI12-0151-1 talks exclusively about incomplete views coming from limited
views. As such, it's possible that we didn't care at all about any changes that
happened for any other kind of access type.


Either way, I'd like to have a decision. If the freezing rule stands, then a
couple existing tests and a number of objectives are unnecessary, and I need to
clean up the ACATS and its documentation to reflect that. And if it is going to
be relaxed somehow, I'm sure the implementer would be interested, and the test
objectives probably will need a couple of additional cases.

For what it's worth, GNAT appears to accept the example package (and its body)
without complaint. I didn't try to create a runnable example, so I don't know
if the result would actually work or if I would get to see one of GNAT's famous
bug boxes. I'll do that IFF there is some interest in exploring whether the
freezing rules should allow examples like this. (Of course, if we confirm the
language, meaning the above is illegal, I'll make a B-Test out of the example
to ensure that it is getting rejected.)

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


Questions? Ask the ACAA Technical Agent