Version 1.1 of ais/ai-00130.txt
!standard H.4 (08) 98-04-08 AI95-00130/02
!class binding interpretation 96-04-13
!status work item 96-04-17
!status received 96-04-13
!priority Medium
!difficulty Medium
!subject Enforcing Restrictions may violate the generic contract model.
!summary 98-04-08
The enforcement of restrictions will generally violate the contract model
of generics, as well as violate the "privateness" of code in a private part
or body.
To be consistent with the No_Task_Hierarchy and No_Nested_Finalization
restrictions, the No_Local_Allocators restriction should not preclude nested
generic instantiations. No_Nested_Finalization is broadened to cover
finalization associated with protected and task objects. For the purposes
of these checks, a generic template is logically expanded at the point
of each instantiation, the type definition for a record or protected
type is logically expanded at the point of any default-initialized object
creation, and default parameter expressions are inserted where used.
!question 96-04-13
H.4(8) says:
No_Local_Allocators
Allocators are prohibited in subprograms, generic subprograms, tasks
and entry bodies; instantiations of generic packages are also
prohibited in these contexts.
Why are instantiations prohibited in these contexts? (This AI allows them.)
The restrictions No_Task_Hierarchy and No_Nested_Finalization do not prohibit
such instantiations.
!recommendation 98-04-08
An implementation supporting the No_Task_Hierarchy, No_Nested_Finalization, or
No_Local_Allocators restrictions must enforce the intent of these restrictions
with compile-time and/or post-compilation checks.
For the purposes of these checks:
- Generic instances are logically expanded at the point of instantiation;
- If an object of a type is declared or allocated and not explicitly
initialized, then all expressions appearing in the definition for
the type and any of its ancestors are presumed to be evaluated
(even for components that are not present in the created object).
- Default formal parameters are presumed to be evaluated only if the
corresponding actual parameter is not provided in a given call or
instantiation;
- Data flow information is not to be used; even "dead" code
should be checked for violations. (??? Is this burdensome
for implementations that completely remove dead code
early? It seems "safe" to ignore dead code so long as
it is "really" dead, i.e., no object code is generated for
it, but of course the check then becomes overly permissive
and hence not as portable. ???)
No_Task_Hierarchy means that only tasks directly dependent on the master
representing the execution of the environment task (body) are permitted.
Tasks dependent on masters which correspond to other bodies or blocks are
not permitted, even if these masters are executed by the environment task.
No_Nested_Finalization should be broadened to mean that objects
requiring finalization due to having a controlled, protected, or task
part are not permitted unless they are at the library level.
No_Local_Allocators means that allocators are prohibited in subprograms,
generic subprograms, task bodies, and entry bodies. As indicated above,
rather than precluding nested instantiations, instantiations are to be
logically expanded at the point of instantiation for the purposes
of this check.
!wording 98-04-08
!discussion 98-04-08
Precluding nested generic instances for the No_Local_Allocators restriction
in H.4(8) in an attempt to preserve a generic control model for restrictions
is inconsistent with the rules for No_Task_Hierarchy given in D.7(3) and
for No_Nested_Finalization given in D.7(4). In general, enforcing
pragma Restrictions across a partition will necessarily violate the
"privateness" of a private part or a body, as well as the generic contract
model.
Although it might be useful to know that if a generic body
does not by itself violate a restriction, then neither will any
instantiation, enforcing this kind of "contract" rule for restrictions
that distinguish library level from non-library level usages would
overly limit the nested instantiations of useful, benign generics.
Furthermore, the pragma Restrictions is primarily designed to
support application environments where schedulability
and formal verification requirements dictate that generics
can only be certified with respected to particular instantiations --
never in the abstract.
A more serious problem with the rules given for the No_Task_Hierarchy
restriction in D.7(3), No_Nested_Finalization in D.7(4), and
No_Local_Allocators in H.4(8), is that they do not properly
account for violations appearing in expressions used for default
parameters and for default initialization.
For example, the following partition obeys the static criteria given in H.4(8)
for the No_Local_Allocators restriction, yet (in the absence of code-removing
optimizations) the main subprogram evaluates an allocator:
package P is
type Integer_Pointer is access Integer;
type R is
record
C: Integer_Pointer := new Integer;
end record;
end P;
with P;
procedure Main is
X: P.R; --
begin
null;
end Main;
To close such loopholes, it is necessary to logically substitute
default initialization and default parameters in line at the point
of usage. However, more or less sophisticated flow analysis might
affect which of the expressions appearing in a record or protected type
definition are presumed to be evaluated as part of the creation of a
default-initialized object of such a type.
To establish implementation-independent rules for enforcing restrictions,
we choose to follow the lead established by the "freezing" rules where
all expressions in a type definition are presumed to be evaluated
if any are evaluated (13.14(15)), whereas expressions for default
parameters are only relevant where the corresponding actual parameter
is omitted (13.14(5,14)). Unlike the freezing rules, an explicitly
initialized object is not presumed to evaluate any of the expressions
inside the corresponding type definition as part of its creation; only
a default initialized object will cause this.
!appendix
[Note: The following comment inadvertently refers to H.4(08) as G.4(08).]
!section G.4(08)
!subject Should No_Local_Allocators disallow nested instantiations?
!reference RM95-G.4(08)
!from Bob Duff
!reference 96-5477.a Robert A Duff 96-4-12>>
!discussion
The following is a bunch of e-mail I got on the subject of whether
No_Local_Allocators should forbid nested instantiations. I think this
deserves an AI. I agree that the restriction should be removed.
- Bob
Date: Fri, 8 Mar 1996 14:53:41 -0500
From: stt@dsd.camb.inmet.com (Tucker Taft)
To: hrg@waffle.cise.npl.co.uk
Subject: Nested instantiations and H.4(8)
A member of the ACVC team brought paragraph H.4(8) to my attention:
No_Local_Allocators
Allocators are prohibited in subprograms, generic subprograms, tasks
and entry bodies; instantiations of generic packages are also
prohibited in these contexts.
The restriction against nested instantiations seems unnecessary and
inconsistent with other restrictions, such as No_Task_Hierarchy
and No_Nested_Finalization. The AARM indicates that the restriction
against nested instantiations is to preserve the generic contract
model. However, there seems no strong argument why the generic
contract model need be preserved by pragma Restrictions.
Pragma restrictions will often require link-time detection
of problems anyway, and so finding out about a problem associated
with an instantiation at that point (which is the down side of not
preserving the generic contract model) seems OK as well.
Hence, I would suggest that the HRG consider removing the part of H.4(8)
that follows the ";", because it is inconsistent with other restrictions,
and unnecessarily restrictive.
-Tuck
Date: Fri, 8 Mar 96 16:11:23 EST
From: dewar@gnat.com (Robert Dewar)
To: hrg@waffle.cise.npl.co.uk, stt@dsd.camb.inmet.com
Subject: Re: Nested instantiations and H.4(8)
Content-Length: 449
what's the point of preserving generic contract model when the lnker will
check for consistency anyway. Moreover, this imitation is a very serious
one from a programming point of view, making the pragma Restrictions
pretty much useless. If this is not changed, then any reasonable
iplementation will have to add
pragma Restrictions (No_Local_Allocators_Sensible_Version);
so I think we should consider this restriction a mistake and remove it.
Date: Mon, 11 Mar 96 09:15:57 GMT
From: Brian A Wichmann <baw@cise.npl.co.uk>
To: hrg@cise.npl.co.uk, stt@dsd.camb.inmet.com
Subject: Re: Nested instantiations and H.4(8)
I am not sure how this restriction came about. Does Bob Duff
have any idea? Removing it seems fine at first glance... Brian.
-------------------------------------------------------------
Brian Wichmann Tele: +44 181 943 6976 (direct)
National Physical Laboratory FAX: +44 181 977 7091
Teddington Middlesex e-mail: baw@cise.npl.co.uk
TW11 0LW
UK
WWW: http://www.npl.co.uk/npl/search/staff?Dr+Brian+Wichmann
-------------------------------------------------------------
****************************************************************
!section G.4(08)
!subject Should No_Local_Allocators disallow nested instantiations?
!reference RM95-G.4(08)
!reference 96-5478.a Robert A Duff 96-4-12
!from Robert I. Eachus
!reference 96-5488.a Robert I. Eachus 96-4-15>>
!discussion
Bob Duff said:
> I agree that the restriction should be removed.
So do I, but I don't agree Tuck:
> Hence, I would suggest that the HRG consider removing the part of H.4(8)
> that follows the ";", because it is inconsistent with other restrictions,
> and unnecessarily restrictive.
I think instead we need to "elaborate" the original intent:
No_Local_Allocators
Allocators are prohibited in subprograms, generic
subprograms, tasks and entry bodies; instantiations of
generic packages _which_contain_allocators_or_task_declarations_
are also prohibited in these contexts.
But this also has an AARM implication. An implementation might
normally implement generic packages by allocating space on the heap,
and in the case of nested packages, recovering the space once the
scope is left. Such an implementation should be forbidden in the
presence of this pragma.
Back to Tuck:
> Pragma restrictions will often require link-time detection
> of problems anyway, and so finding out about a problem associated
> with an instantiation at that point (which is the down side of not
> preserving the generic contract model) seems OK as well.
Notice that it is only nested generic package instantiations that
are forbidden. Nested generic subprogram instantiations are permitted
and instantiations with formal private type parameters could require
the link time check:
generic
type Fubar is private;
procedure Foob;
procedure Foob is
X: Fubar;
begin ... end Foob;
...
procedure Main is
type Foo is record
Bar: Pointer := new Hidden_Allocator;
end record;
procedure FB is new Foob(Foo);
....
(Gee, running low on metavariables there...)
Since, absent the pragma there is no dependence of the body of Main
on the body of Foob, the violation of the pramga must be detected
after compile time.
****************************************************************
>From the minutes of the November 1997 ARG meeting:
Erhard argues, in a separate e-mail message, against the current
position of the AI because it breaks the contract model and requires
too much link time mechanism to enforce the restriction. Instead
enforcing the currently stated restriction of only library-level
instantiations will enforce the contract model by doing a compile-time
check.
Pascal and Robert then noted that there is a much deeper problem here.
Record components with default initialization, protected objects with
initialization of their state, default values for parameters all share
the property that allocations might happen that are not apparent at
source level. The current semantics of No_Local_Allocation does not
cover these cases at all. Since these types can be private, the
privateness principle will need to be broken for compile-time
checks. The group could not come up with "circumstantial" restrictions
that would otherwise ensure the absence of such implicit allocation
without being extremely and unacceptably over-restrictive. In
passing, it was noted that the strict predicate of No_Local_Allocators
is actually value-dependent (and hence undecidable), since a
default-initialized component might be located in a non-existent
variant of a constrained record object.
There is a concern that this sets a precedence for exposing more
implementation information about types, which violates the spirit of
abstract data type information hiding (and will cause problems in some
compilers). But the Restrictions facility is inherently
implementation focused (especially restrictions like this one that
deal with nested usage, No_Nested_Finalization and No_Task_Hierarchy
being the other ones) and therefore some exposure of the
implementation details of imported types (such as Text_IO that uses
allocated data for file_type) must be made in order to enforce the
Restrictions. This will affect semantic analysis involving private
types because now uses of private types will need to check that they
adhere to restrictions relating to previously hidden features of the
private type.
The No_Task_Hierachy and No_Nested_Finalization restrictions share the
same problem, since components might be tasks or of controlled type.
It is not clear what the language can do about the portability of
these three pragmas and still be effective.
It was even suggested that these three restrictions should not be in
the language, after all, since the benefits do not justify the costs.
ASIS-based analysis tools were mentioned as an alternative
restriction-enforcing mechanism.
Norm then suggested to take a step back and reformulate the semantics
of the pragma from the viewpoint of intended usage, and leave the
formulation of secondary restrictions to the implementation. He will
rewrite to emphasize usefulness over portability; he will coordinate
with Erhard on the write-up.
****************************************************************
--------------------------------------------------------------------------------
Questions? Ask the ACAA Technical Agent