CVS difference for ai05s/ai05-0051-1.txt
--- ai05s/ai05-0051-1.txt 2008/01/29 04:02:04 1.5
+++ ai05s/ai05-0051-1.txt 2008/02/05 05:27:02 1.6
@@ -1,4 +1,4 @@
-!standard 6.5(21/2) 08-01-27 AI05-0051-1/04
+!standard 6.5(21/2) 08-02-03 AI05-0051-1/05
!class binding interpretation 07-05-04
!status work item 07-05-04
!status received 07-04-19
@@ -121,16 +121,18 @@
as that of the level of the master that elaborated the function
body.
-Modify 6.5(8/2) as follows:
+Modify 6.5(8/2) as follows (The original text includes the wording changes
+from AI05-0024-1 and AI05-0032-1):
If the result type of a function is a specific tagged type, the tag
of the return object is that of the result type. If the result type
- is class-wide, the tag of the return object is that of the value of
- the expression. A check is made that the accessibility level of the
- type identified by the tag of the result is not deeper than that of
- the [master that elaborated the function body] {the level of the
- return object as determined by the point of call (see 3.10.2)}. If
- this check fails, Program_Error is raised.
+ is class-wide, the tag of the return object is that the type of the
+ subtype_indication if it is specific, or otherwise that of of the
+ value of the expression. A check is made that the master of the type
+ identified by the tag of the result includes the elaboration of the
+ master [that elaborated the function body] {of the return object as
+ determined by the point of call (see 3.10.2)}. If this check fails,
+ Program_Error is raised.
Modify 6.5(21/2) as follows:
@@ -2003,5 +2005,509 @@
Do_Something (new Lim_T'(Blurfo)); -- OK.
Do_Something (Blah); -- Runtime error. Yuck.
end Nested;
+
+****************************************************************
+
+From: Tucker Taft
+Sent: Monday, January 28, 2008 10:27 PM
+
+...
+> Your wording has (in several places):
+>
+> "...is determined as though the allocator were in place of the call of the
+> function..."
+>
+> "were in place of" doesn't make much sense to me. I know that you mean
+> "...as though the allocator were given at the place of the call..." -- so
+> why didn't you say that? I think it's a lot clearer.
+
+Actually, I meant what I wrote. I'm using the phrase
+"be in place of" in its sense of "substitute." I think
+it is grammatically correct to use the subjunctive
+"as though A were in place of B" in the sense of
+"as though A were substituted for B." Perhaps
+I should have used the word "substituted."
+
+
+> ---
+>
+> The wording change of 6.5(8/2) doesn't take AI05-0024-1 into account. That's
+> OK, other than that it means that a simple level comparision will not do for
+> this check. That means that the check will be quite expensive - and that
+> means that something that looks cheap (anonymous return types) will be
+> anything but cheap. Since the level will be passed in, there won't be any
+> practical way (short of inlining) to eliminate this check (unlike the
+> current semantics).
+
+The change in 6.5(8/2) deals with a special case
+having to do with accept statements. I'm not
+too worried if code inside of accept statements
+that fiddles around with accessibility levels
+is a bit more expensive. Do you think there is
+some distributed overhead as well? I think the
+check will generally be a simple level comparison,
+similar to the one currently used with access
+parameters.
+
+...
+> But it depends on the type conversion being at the point of the call (which
+> is why I call it a hack).
+
+I think you are mistaken (see below).
+
+> ... That isn't necessarily true. Consider:
+>
+> procedure Do_Something (A : access Lim_T) is
+> X : Lim_T_Ptr := Lim_T_Ptr(A);
+> begin
+> ...
+> end Do_Something;
+>
+> Do_Something (new Lim_T'(Blurfo)); -- OK.
+> Do_Something (Blah); -- OK.
+
+These both fail the accessibility check associated
+with the type conversion, because they are both
+allocated at a level associated with the innermost
+master of the call, which in this case is the
+procedure call statement. That is more nested than
+Lim_T_Ptr.
+
+> procedure Nested is
+> begin
+> Do_Something (new Lim_T'(Blurfo)); -- OK.
+> Do_Something (Blah); -- Runtime error. Yuck.
+
+These also both fail.
+
+> end Nested;
+
+*****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, January 28, 2008 10:54 PM
+
+...
+> Actually, I meant what I wrote. I'm using the phrase
+> "be in place of" in its sense of "substitute." I think
+> it is grammatically correct to use the subjunctive
+> "as though A were in place of B" in the sense of
+> "as though A were substituted for B." Perhaps
+> I should have used the word "substituted."
+
+I think "substituted" would be better. "in place of" is much too close
+to "at the place of". But I still think "given at the place of" is best,
+because I don't think "substitute" quite reflects what is going on
+(especially in the case of access discriminants, where you surely aren't
+substituting the whole call with just one of the discriminants).
+
+> > ---
+> >
+> > The wording change of 6.5(8/2) doesn't take AI05-0024-1 into account. That's
+> > OK, other than that it means that a simple level comparision will not do for
+> > this check. That means that the check will be quite expensive - and that
+> > means that something that looks cheap (anonymous return types) will be
+> > anything but cheap. Since the level will be passed in, there won't be any
+> > practical way (short of inlining) to eliminate this check (unlike the
+> > current semantics).
+>
+> The change in 6.5(8/2) deals with a special case
+> having to do with accept statements. I'm not
+> too worried if code inside of accept statements
+> that fiddles around with accessibility levels
+> is a bit more expensive. Do you think there is
+> some distributed overhead as well? I think the
+> check will generally be a simple level comparison,
+> similar to the one currently used with access
+> parameters.
+
+I do think that there is some distributed overhead that comes from this
+rule. With the old rule, most of the accessibility checks for return
+statements can be done at compile-time, so there is no check code at all.
+With this rule, all functions need check code. And that check code cannot be
+a "simple level comparison", because that would allow bad stuff (the accept
+cases we've talked about). A function cannot generate code assuming how it
+will be called!
+
+...
+> > ... That isn't necessarily true. Consider:
+> >
+> > procedure Do_Something (A : access Lim_T) is
+> > X : Lim_T_Ptr := Lim_T_Ptr(A);
+> > begin
+> > ...
+> > end Do_Something;
+> >
+> > Do_Something (new Lim_T'(Blurfo)); -- OK.
+> > Do_Something (Blah); -- OK.
+>
+> These both fail the accessibility check associated
+> with the type conversion, because they are both
+> allocated at a level associated with the innermost
+> master of the call, which in this case is the
+> procedure call statement. That is more nested than
+> Lim_T_Ptr.
+
+Yuck! Again, an anonymous access type does the wrong thing. Is there any
+case where accessibility and/or anonymous access types actually do something
+useful in Ada?? (No, don't answer that. ;-)
+
+<start gripe>
+Anonymous access types are one of the worst ideas ever put into Ada. All of
+bizarre rules for accessibility, coextensions, and finalization issues --
+and there is no sign that we're remotely close to getting these "right". And
+then they're not really intuitive. All of this crap because we were
+unwilling to have in out parameters on functions. Bleeh!
+<end gripe>
+
+*****************************************************************
+
+From: Tucker Taft
+Sent: Monday, January 28, 2008 11:34 PM
+
+> I do think that there is some distributed overhead that comes from this
+> rule. With the old rule, most of the accessibility checks for return
+> statements can be done at compile-time, so there is no check code at all.
+> With this rule, all functions need check code. And that check code cannot be
+> a "simple level comparison", because that would allow bad stuff (the accept
+> cases we've talked about). A function cannot generate code assuming how it
+> will be called!
+
+I'll have to restudy AI05-0024-1, but I don't think most code
+needs to worry about it at all, unless it is *lexically* nested
+inside of a task body. Are you implying that any old function
+that gets an access parameter can't use a simple level
+check to see whether it can convert it to a named access
+type, presuming it is not lexically inside a task body?
+That surprises me, to say the least.
+
+*****************************************************************
+
+From: Randy Brukardt
+Sent: Monday, January 28, 2008 11:59 PM
+
+Umm, 6.5(8/2) is the *class-wide* accessibility check, not the access
+accessibility check. Although it looks like the access check gets
+involved too. And it's pretty obvious that you can trigger the problem
+in a function.
+
+Here's the original example, suitably changed:
+
+ declare
+ type T1 is tagged null record;
+
+ function Something (Default : in T1'Class) return access T1'Class is
+ begin
+ ...
+ return new T1'Class(Default);
+ end Something;
+
+ task T is
+ entry E (X : T1'Class);
+ end T;
+
+ task body T is
+ type Ref2 is access T1'Class;
+ R2 : Ref2;
+ begin
+ accept E (X : T1'Class) do
+ R2 := new T1'Class'(X); -- Original problem case.
+ R2 := Ref2(Something (X)); -- New problem case.
+ end;
+ -- Delay for a while and then do nasty things with R2.
+ end;
+
+ procedure Proc is
+ type T2 is new T1 with null record;
+ X2 : T2;
+ begin
+ T.E (X2);
+ end;
+
+ begin
+ Proc;
+ end;
+
+In the accept statement, X is passed in and the complex check is needed
+for the direct allocator (otherwise we get trouble because the type has
+gone before the object).
+
+By your proposed rules, the call to Something has the same accessibility
+as Ref2, and thus the allocator inside of Something needs the same sort
+of complex check as the allocator directly inside of the accept statement.
+
+Notice that the function and the task could declared far apart. Indeed,
+the function has to be capable of handling the case, even if there is
+no task in existence. Moreover, unless you are willing to peek into
+the body, the function has to have the complex check (and the complex
+data passed in to support it) even if it doesn't return the classwide object.
+
+A similar check is needed for a class-wide object return (in this case, if
+Something returned Obj directly).
+
+I'm not sure if there is any way to trigger this problem without a tagged
+parameter. If not, I suppose it would be possible to have two kinds of
+checks, and only use the complex one if the profile includes a tagged
+parameter and returns a class-wide type or tagged type.
+
+But this sure sounds distributed to me...
+
+*****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, January 29, 2008 12:09 AM
+
+> I'll have to restudy AI05-0024-1, but I don't think most code
+> needs to worry about it at all, unless it is *lexically* nested
+> inside of a task body.
+
+Under your new rule, it only matters where the *call* is lexically
+nested.
+
+I suppose you could generate two bodies for every affected function,
+one with a simple check and one with the complex check. That would
+eliminate the overhead other than in the bad calls. But if you're
+seriously suggesting that, I'd have to suggest a check of your
+sanity...
+
+*****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, January 29, 2008 12:14 AM
+
+(Sorry, I keep hitting "Send" and then thinking of something else I should have said...)
+
+...
+> Are you implying that any old function
+> that gets an access parameter can't use a simple level
+> check to see whether it can convert it to a named access
+> type, presuming it is not lexically inside a task body?
+
+Possibly, since you can call a function from inside aof an accept statement.
+If Something had been declared:
+ function Something (Ptr : access T1'Class) return access T1'Class is
+ begin
+ return Ptr;
+ end Something;
+
+and the call was
+
+ R2 := Ref2(Something (X'Access)); -- Still gotta problem.
+
+But I think the parameter has to be access-to-tagged to cause the problem,
+so it isn't *every* function.
+
+Note that the class-wide check has a similar issue:
+ function Something (Ptr : not null access T1'Class) return T1'Class is
+ begin
+ return Ptr.all;
+ end Something;
+
+*****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, January 29, 2008 12:33 AM
+
+One way to minimize the distributed overhead
+would be to only do the more expensive check
+if the simple level-based check *fails.*
+Presumably the passed-in level can be chosen
+so that it will be quite rare that the expensive
+check will pass while the cheap check will fail.
+And the more expensive check seems to be relevant
+only when checking a class-wide type.
+
+*****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, January 29, 2008 12:49 AM
+
+I suppose, but I would expect that the primary extra cost would simply be
+the need to pass in the more complex data needed to do the complex check.
+(And to pass it along with access parameters.) Most of the time, even the
+expensive check will succeed very quickly (most things are library level,
+after all, or nested a single level). So I'm not sure it is worth it to
+duplicate that code.
+
+But surely there is a distributed space overhead, because of the more
+complex checks and the more complex data to support them.
+
+*****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, January 29, 2008 7:55 AM
+
+...
+> Possibly, since you can call a function from inside aof an accept statement.
+> If Something had been declared:
+> function Something (Ptr : access T1'Class) return access T1'Class is
+> begin
+> return Ptr;
+> end Something;
+>
+> and the call was
+>
+> R2 := Ref2(Something (X'Access)); -- Still gotta problem.
+
+I don't think so, since access parameters can't be passed
+via an entry call, so you never get two different stacks
+involved in the accessibility of an access parameter.
+So I believe you never need more than a simple level for
+an access parameter.
+
+*****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, January 29, 2008 7:58 AM
+
+I think your access parameter example is
+incorrect. I believe the only time you
+get two different stacks involved in
+accessibility is a check on the level associated
+with a tag, and then presumably the information
+you need is carried with the tag or with the
+allocation context you need to pass for these
+kinds of functions anyway.
+
+*****************************************************************
+
+From: Randy Brukardt
+Sent: Tuesday, January 29, 2008 1:18 PM
+
+> I don't think so, since access parameters can't be passed
+> via an entry call, so you never get two different stacks
+> involved in the accessibility of an access parameter.
+> So I believe you never need more than a simple level for
+> an access parameter.
+
+Humm, I think you're wrong. The two stacks get involved because I took the
+'Access of an item on a different stack. Perhaps it's easier to see in a
+complete example:
+
+ declare
+ type T1 is tagged null record;
+
+ function Something (Ptr : access T1'Class) return access T1'Class is
+ begin
+ return Ptr;
+ end Something;
+
+ task T is
+ entry E (X : T1'Class);
+ end T;
+
+ task body T is
+ type Ref2 is access T1'Class;
+ R2 : Ref2;
+ begin
+ accept E (X : T1'Class) do
+ R2 := new T1'Class'(X); -- Original problem case.
+ R2 := Ref2(Something (X'Access)); -- New problem case.
+ end;
+ -- Delay for a while and then do nasty things with R2.
+ end;
+
+ procedure Proc is
+ type T2 is new T1 with null record;
+ X2 : T2;
+ begin
+ T.E (X2);
+ end;
+
+ begin
+ Proc;
+ end;
+
+Since the accessibility of the anonymous return subtype comes from the call
+in your new rule, you have to be able to make the full check. And the
+accessibility of anonymous access parameters come from the actual object. So
+it looks like we have the full complexity here.
+
+*****************************************************************
+
+From: Tucker Taft
+Sent: Tuesday, January 29, 2008 12:10 PM
+
+When you take 'Access of a formal parameter of a
+tagged type, it is treated like a local variable.
+Hence, in your example the accessibility passed
+via the access parameter associated with "X'Access"
+is guaranteed to be on the same stack as the task
+itself, and can't come from the entry caller's
+stack. See below.
+
+...
+> Humm, I think you're wrong. The two stacks get involved because I took the
+> 'Access of an item on a different stack.
+
+You took 'Access of a formal parameter, and that is always
+treated like a local variable (since "normal" formals
+don't carry along their own accessibility level from
+the actual -- only access parameters do, and we don't
+allow those).
+
+> ... Perhaps it's easier to see in a
+> complete example:
+>
+> declare
+> type T1 is tagged null record;
+>
+> function Something (Ptr : access T1'Class) return access T1'Class is
+> begin
+> return Ptr;
+> end Something;
+>
+> task T is
+> entry E (X : T1'Class);
+> end T;
+>
+> task body T is
+> type Ref2 is access T1'Class;
+> R2 : Ref2;
+> begin
+> accept E (X : T1'Class) do
+> R2 := new T1'Class'(X); -- Original problem case.
+> R2 := Ref2(Something (X'Access)); -- New problem case.
+> end;
+> -- Delay for a while and then do nasty things with R2.
+> end;
+>
+> procedure Proc is
+> type T2 is new T1 with null record;
+> X2 : T2;
+> begin
+> T.E (X2);
+> end;
+>
+> begin
+> Proc;
+> end;
+>
+> Since the accessibility of the anonymous return subtype comes from the call
+> in your new rule, you have to be able to make the full check. And the
+> accessibility of anonymous access parameters come from the actual object.
+
+True, but the actual object (X) in this case is a formal parameter,
+which is treated like a local variable. It is true that the
+accessibility associated with the tag of T2 has the "full complexity,"
+but there are never two stacks involved when passing the accessibility
+level of an access parameter.
+
+> ... So
+> it looks like we have the full complexity here.
+
+Access parameters never have the "full" complexity,
+thanks to the fact that we don't allow them in
+entry calls.
+
+*****************************************************************
+
+From: Tucker Taft
+Sent: Monday, February 4, 2008 5:06 PM
+
+Randy pointed out that we had already revised 6.5(8/2),
+which this AI also touches. So this version [/05 - ED] is based
+on the latest 6.5(8/2), but is otherwise identical
+to version 4 sent earlier.
*****************************************************************
Questions? Ask the ACAA Technical Agent