AI22-0042-1

!standard 13.14(15.1/3)                                       22-06-14  AI22-0042-1/01

!class binding interpretation 22-06-14

!status work item 22-06-14

!status received 22-06-09

!priority High

!difficulty Easy

!qualifier Omission

!subject Freezing rule needed for dispatching expression functions

!summary

If an expression function is a dispatching operation, then it can be called without explicitly naming the expression function in the call. Thus, the freezing of the tagged type needs to freeze the return expression of the function, just as 13.14(10.3/4) does for Access attribute references (which also allow calling a function without explicitly naming it in the call).

!issue

The expression of an expression function does not cause freezing when the expression function is declared. Instead, such freezing is deferred until the function is called. This handles the case of direct calls, but indirect calls must also be dealt with. Another rule handles the case of an indirect call via an access-to-subprogram value; such a call must be preceded by an Access (or Unchecked_Access) attribute reference in order to construct the needed access value, and that

Attribute reference causes the needed freezing. But there appears to be a hole in the case of a dispatching call. Should this example be legal? (No.)

with Text_IO;
procedure Peculiar_Size is
  package Pkg1 is
     type T1 is tagged null record;
     function Prim (X1 : T1) return Integer;
  end Pkg1;
  package body Pkg1 is
     function Prim (X1 : T1) return Integer is
     begin
        return 1;
     end Prim;
  end Pkg1;
  package Pkg2 is
     type Priv is private;
     type Rec is record Aaa, Bbb : Priv; end record;

     type T2 is new Pkg1.T1 with null record;
     overriding function Prim (X2 : T2) return Integer is (Rec'Size);

     Obj : Pkg1.T1'Class := T2'(null record);
     -- T2 is frozen here; Rec is not completely defined.

     Sz  : constant Integer := Pkg1.Prim (Obj);
  private
     --  Priv'Size depends on Priv'Last, which depends on Rec'Size,
     --  which depends on Priv'Size; a cyclic dependency.
     type Priv is new String (1 .. Sz);
  end Pkg2;

  package body Pkg2 is
  begin
     Text_IO.Put_Line ("Priv'Last =" & Priv'Last'Image);
     Text_IO.Put_Line ("Rec'Size =" & Integer'(Rec'Size)'Image);
  end Pkg2;
begin
  null;
end Peculiar_Size;

Informally speaking, one can view the construction of a tagged type’s dispatch table (which occurs no later than when the type is frozen) as including an implicit Access attribute reference for each primitive subprogram. With this model in mind, it makes sense that the freezing of a tagged type should cause the same freezing for each primitive subprogram (and, in particular, for each primitive expression function) as would have been caused by an Access attribute reference which designates that subprogram.

!recommendation

Treat the freezing of a tagged type with a primitive expression function similarly (with respect to freezing) to an Access attribute reference that designates the function.

!wording

Modify 13.14(15.1/3):

At the place where a specific tagged type is frozen, the primitive subprograms of the type are frozen {; for each such primitive subprogram that is an expression function, its return_expression causes freezing}.

!discussion

The proposed wording matches the wording used in 13.14(10.3) for Access attribute references.

One might think that this new freezing is only necessary if the expression function overrides an inherited primitive subprogram. This is not the case, as can be demonstrated with a variation of the given example that uses an interface type.

Tucker notes that 13.14(10.3/4) mentions a non-existent Unchecked_Access attribute of a function. We could consider fixing that, but it wasn’t done in this AI to keep it simple.

!example

(See issue.).

!ACATS test

A B-test similar to the given example could be written.

!appendix