Version 1.1 of ai05s/ai05-0281-1.txt
!standard 3.10.2(12/2) 11-11-12 AI05-0281-1/01
!standard 3.10.2(12.1/2)
!standard 3.10.2(12.5/3)
!class ramification 11-11-12
!status ARG Approved 5-0-4 11-11-12
!status work item 11-11-08
!status received 11-09-26
!priority Low
!difficulty Hard
!qualifier Omission
!subject Accessibility of access discriminants of a subtype
!summary
The subtype_indication mentioned in 3.10.2(12.1/2) is not necessarily declared
at the place of the check (which is an allocator or return statement); it could
be declared in a separate declaration elsewhere.
!question
Consider:
procedure Condit_Expr_Accessibility is
Flag : Boolean := True;
Test_Failed : exception;
type Drec (Int_Ref : access Integer) is null record;
type Global_Ref is access Drec;
Global_Ptr : Global_Ref;
Global_Var : aliased Integer;
procedure Nested is
type Local_Ref is access Drec;
Local_Ptr : Local_Ref;
Local_Var : aliased Integer;
function Checker return Drec is
--
--
subtype S is Drec
(Int_Ref => (if Flag then Local_Var'access
else Global_Var'access));
begin
Flag := False;
return X : S;
end Checker;
begin
Local_Ptr := new Drec'(Checker);
--
--
--
--
Flag := True;
begin
Global_Ptr := new Drec'(Checker);
--
--
--
--
raise Test_Failed;
exception
when Program_Error =>
null;
end;
end Nested;
begin
Nested;
end Condit_Expr_Accessibility;
In order to make the return accessibility check, we need to know the accessibility
of S.Int_Ref. 3.10.2(12.1/2) does not apply (because this is not in an allocator
or return statement), so we use 3.10.2(12.5/3). But that says that it is the
"accessibility of the enclosing object" -- and there is no enclosing object.
Is this right? (No.)
!response
The subtype_indication mentioned in 3.10.2(12.1/2) is not necessarily declared in
the allocator or return statement; the check has to occur in one of those contexts,
but not the declaration of the subtype. So 3.10.2(12.1/2) does apply, and there
is no problem.
!wording
Add an AARM note after 3.10.2(12.d/2) to clarify this:
The subtype_indication mentioned in this bullet is not necessarily the one given in
the allocator or return statement that is determining the accessibility level; the
constrained subtype might have been defined in an earlier declaration (as a named
subtype).
!discussion
It would be nice to make this clearer in the normative wording, but this wording
is clear as mud already, so messing with it further is unlikely to help. Thus we
just add an AARM note.
!ACATS Test
An ACATS C-Test should be created (but this is likely to be low priority).
!ASIS
No ASIS impact.
!appendix
From: Steve Baird
Sent: Monday, September 26, 2011 5:24 PM
The following issue came up while reviewing interactions
between conditional expressions and accessibility, but it seems
that conditional expressions are not an essential part of the
problem.
Consider:
procedure Condit_Expr_Accessibility is
Flag : Boolean := True;
Test_Failed : exception;
type Drec (Int_Ref : access Integer) is null record;
type Global_Ref is access Drec;
Global_Ptr : Global_Ref;
Global_Var : aliased Integer;
procedure Nested is
type Local_Ref is access Drec;
Local_Ptr : Local_Ref;
Local_Var : aliased Integer;
function Checker return Drec is
-- Flag is always True at this point, but the
-- compiler doesn't know that.
subtype S is Drec
(Int_Ref => (if Flag then Local_Var'Access
else Global_Var'Access));
begin
Flag := False;
return X : S;
end Checker;
begin
Local_Ptr := new Drec'(Checker);
--
-- for the above call, it is ok for
-- Checker to return a result which
--- references Local_Var
Flag := True;
begin
Global_Ptr := new Drec'(Checker);
--
-- for the above Call, returning
-- a result which references Local_Var
-- should fail an accessibility check
raise Test_Failed;
exception
when Program_Error =>
null;
end;
end Nested;
begin
Nested;
end Condit_Expr_Accessibility;
On returning from Checker, we need to perform a check
that the discriminant of the result designates something
which is sufficiently long-lived:
RM 6.5:
A check is made that the accessibility level of the anonymous
access type of each access discriminant, as determined by the
expression or the return_subtype_indication of the return
statement, is not deeper than the level of the master of
the call (see 3.10.2)
So in this case, what is the "accessibility level of the anonymous
access type of each discriminant". What is the accessibility level
of, speaking loosely, the type of S.Int_Ref?
I don't believe that 3.10.2 handles this case correctly, Strictly
speaking, I think it falls into the "when others" handler:
The accessibility level of the anonymous access type of an access
discriminant in any other context is that of the enclosing object.
This is obviously absurd (there is no enclosing object - S is a
subtype).
One solution would be to use the rule that is currently used only
in the special case where the subtype_indication in question is the
subtype_indication for an extended return statement or for an
allocator:
If the value of the access discriminant is determined by a
discriminant_association in a subtype_indication, the
accessibility level of the object or subprogram designated
by the associated value (or library level if the value is null)
It seems clear that this rule was very explicitly intended only for
the special cases of allocators and return statements.
Was this an oversight?
****************************************************************
!response
The rules clearly were intended to apply only to "original" declarations,
and not the declaration of a completion. No user or implementer is going
to misinterpret these rules, given that a literal interpretation would
prevent the declaration of any concrete tagged type with primitive operations
(those operations could never be completed).
Moreover, one could argue that subprogram declarations in a body are not
primitive subprograms - whether or not completions of a primitive subprogram
also is a primitive subprogram when a stand-alone subprogram would not be
primitive is not clearly addressed by 3.2.3(2-7) -- a literal reading would
say that they are not.
But that would just make the issue even more confusing.
With the unlikelyhood of misinterpretation, we simply add a To Be Honest note
to the AARM to make it crystal clear that completions are not considered.
Note the introduction of expression functions by AI05-0177-1 makes this a more
significant issue. We would not want the following to be illegal:
package Pak2 is
type T is tagged private;
function F (Obj : T) return Boolean;
private
type T is tagged record
Flag : Boolean;
end record;
Object : T; -- Freezes T.
function F (Obj : T) return Boolean is (Obj.Flag);
end Pak2;
!wording
Add a new AARM note after 3.9.2(13) and after 13.14(16):
AARM To Be Honest: This rule only applies to "original" declarations and
not to the completion of a primitive subprogram, even though a completion
is technically an explicit declaration, and it may declare a primitive
subprogram.
!ACATS Test
An ACATS test could be constructed for the expression function case (the
example of the question is too much of a pathology to matter).
!ASIS
This has no impact on ASIS.
!appendix
!topic Subprogram body declarations and 3.9.2(13)
!reference RM 3.9.2(13), 13.14(16), 6.3(5)
!from Adam Beneschan 10-03-25
!discussion
This is a wording nitpick that I'm not sure really needs to be fixed:
package Pak1 is
type T1 is tagged record ... end record;
procedure Op (X : in out T1);
end Pak1;
with Pak1;
procedure Proc2 is
type T2 is new Pak1.T1 with record ... end record;
overriding
procedure Op (X : in out T2);
Var : T2;
overriding
procedure Op (X : in out T2) is -- (A)
begin
...
end Op;
...
Shouldn't cause any problems, right? Op (on T2) is declared before
Var, which is before T2 is frozen.
However, the way things are worded:
3.9.2(13): "The explicit declaration of a primitive subprogram of a
tagged type shall occur before the type is frozen."
6.3(5): "A subprogram_body is considered a declaration. It can either
complete a previous declaration, or itself be the initial declaration
of the subprogram."
one could think that since line (A) is a declaration, and it's
occurring after the type is frozen, that 3.9.2(13) makes it illegal.
Perhaps the intent is so obvious that no fix is needed; but if it's
considered incorrect, then changing 3.9.2(13) and 13.14(16) to
something like
The explicit declaration (that is not the completion of a previous
declaration) of a primitive subprogram of a tagged type shall occur
before the type is frozen.
would work.
****************************************************************
Questions? Ask the ACAA Technical Agent