Version 1.9 of ais/ai-00329.txt

Unformatted version of ais/ai-00329.txt version 1.9
Other versions for file ais/ai-00329.txt

!standard 6.05.01 (01)          04-11-04 AI95-00329/06
!standard 11.04.01 (04)
!standard 11.04.01 (14)
!class amendment 03-03-04
!status Amendment 200Y 04-03-24
!status WG9 Approved 04-06-18
!status ARG Approved 9-0-1 04-03-06
!status work item 03-03-04
!status received 03-03-04
!priority Medium
!difficulty Medium
!subject pragma No_Return -- procedures that never return
!summary
Pragma No_Return specifies that a procedure never returns "normally" but rather can return only by propagating an exception.
Ada.Exceptions.Raise_Exception is changed to always raise an exception, and has pragma No_Return apply to it. If Raise_Exception is passed Null_Id, it raises Constraint_Error, like several of the other operations in Ada.Exceptions.
!problem
As Ada compiler and other tools do more static analysis of source code to identify possible errors, it is important to know whether it is possible for a call on a given procedure to return or not. For example, it is relatively common to have a "Fatal_Error" procedure in an application, which displays an error message or logs the error, and then raises an exception or somehow terminates the program. It would be useful for the compiler, and the human reader, to know that any call on such a procedure will never return. This will allow the compiler to provide better warnings about functions that end without returning, about possibly uninitialized variables, about dead code, etc.
!proposal
pragma No_Return(local_name {, local_name});
This pragma is a program unit pragma, and is modeled after the Inline pragma, and has similar syntax, name resolution, and legality rules, except that it only applies to procedures (not functions).
If a procedure has such a pragma, then return statements are illegal in the procedure, and Program_Error is raised if the procedure completes normally by reaching the end of its body (just as with a function).
Change the definition of Ada.Exceptions.Raise_Exception to raise Constraint_Error if given Null_Id, and mark it as a No_Return procedure.
!wording
Add new clause:
6.5.1 Pragma No_Return
A pragma No_Return indicates that a procedure can return only by propagating an exception.
Syntax
The form of a pragma No_Return, which is a program unit pragma (see 10.1.5), is as follows:
pragma No_Return(local_name {, local_name});
Legality Rules
The pragma shall apply to one or more procedures or generic procedures.
If a pragma No_Return applies to a procedure or a generic procedure, there shall be no return_statements that apply to that procedure.
Static Semantics
If a pragma No_Return applies to a generic procedure, pragma No_Return applies to all instances of that generic procedure.
Dynamic Semantics
If a pragma No_Return applies to a procedure, then the exception Program_Error is raised at the point of the call of the procedure if the procedure body completes normally.
Add after 11.4.1(4):
pragma No_Return(Raise_Exception);
Modify 11.4.1(14) as follows:
[Raise_Exception and] Reraise_Occurrence [have] {has} no effect in the case of [Null_Id or] Null_Occurrence. {Raise_Exception,} Exception_Message, ...
!example
procedure Fatal_Error(Msg : String); pragma No_Return(Fatal_Error);
function A_OK(X : Integer) return Integer is begin if X = 0 then Fatal_Error("Divide by zero"); else return 2**30 / X; end if; end A_OK;
By placing the pragma No_Return on a procedure, calling it is effectively equivalent to raising an exception from the point of view of the compiler, so the above should not produce a warning that the function A_OK might end without executing a return statement. Similarly:
procedure Also_A_OK(Phase_Of_The_Moon : Float) is X, Y : Integer; begin if Phase_Of_The_Moon = 1.0 then Fatal_Error("Full moon"); else X := 42; end if; Y := X; Put_Line("Y = " & Integer'Image(Y)); end Also_A_OK;
The above should not generate a warning that X might be uninitialized when assigned to Y.
!discussion
Although the above examples are fairly mundane, there are more serious cases where knowing that a procedure will never return is critical for verifying or simply for understanding an algorithm.
GNAT already supports this pragma, and it was recently added to the AdaMagic front end to allow the compiler to do a better job of producing warnings in the presence of procedures like "Fatal_Error".
It is not uncommon to have a coding discipline that any compiler warning should be considered an error, and code must be changed to eliminate any warnings. However, without a pragma like "No_Return", this can become difficult and can obscure the true functioning of the code. Furthermore, it generally requires the insertion of dead code, which is anathema to most program certification requirements.
We considered various rules regarding the meaning of No_Return. One possibility was that it simply meant that the compiler could presume the procedure wouldn't return from the point of view of compile-time warnings, but it would still be OK if the procedure did in fact return. However, that seemed like a recipe for implementation complexity, since the compiler optimizer is being encouraged to assume something that might be false, which is a good way to create havoc. Hence, we have simply adopted the rule for functions, namely that Program_Error is raised if a No_Return procedure "successfully" reaches the end of its body. Coupled with making return statements illegal, we ensure that the caller is guaranteed that the procedure does not return normally. (Of course, it would be possible for an "imported" procedure to violate this, but this clearly should be erroneous.)
We also considered rules that would allow return statements, but require that they could not be "reached." However, we rejected basing legality rules on control flow analysis, since that would seem to be a dangerous precedent to set at this point, since there are current Ada compilers that at least in some modes don't do any flow analysis.
Originally we considered allowing No_Return on functions, but that seemed of little benefit, and outlawing return statements in functions would clearly conflict with the existing (albeit a bit weird) rule that currently requires at least one.
Note that the existing GNAT pragma No_Return makes it illegal to "reach" the end of the procedure body, but as explained above, we felt it was unwise to use reachability in a legality rule.
The proposed rule is upward compatible with existing users of the GNAT pragma No_Return, since they currently must abide by the stricter rule of unreachable end of body. Also, presumably compilers that currently warn about possibly reachable end-of-function can generalize the warning to apply to No_Return procedures as well, so the safety provided by the GNAT rule can be preserved presuming GNAT users take warnings seriously. (We guess they do in that GNAT has a "treat warnings as errors" flag.)
Raise_Exception
The existing situation where Raise_Exception has no effect when passed Null_Id seems to be of little value. Being able to declare Raise_Exception as a No_Return procedure would have significant value, since it is essentially always used that way. To be consistent with other subprograms in this package, it would seem best to raise Constraint_Error when Raise_Exception is given a Null_Id (though Program_Error would be another reasonable choice).
We considered having this pragma apply to Ada.Exceptions.Reraise_Occurrence as well. It has no effect when Null_Occurrence is passed, and that would need to change in order to apply the pragma. However, it is not unusual to pass the occurrence of an exception to other code to delay raising it. If there was no exception, passing Null_Occurrence for this works fine. Moreover, as there is no test for Null_Occurrence in Ada 95, this is the only way to write such code without additional flags. Thus, we considered the incompatibility unacceptable for Reraise_Occurrence.
!corrigendum 6.5.1(1)
Insert new clause:
A pragma No_Return indicates that a procedure can return only by propagating an exception.
Syntax
The form of a pragma No_Return, which is a program unit pragma (see 10.1.5), is as follows:
pragma No_Return(local_name{, local_name});
Legality Rules
The pragma shall apply to one or more procedures or generic procedures.
If a pragma No_Return applies to a procedure or a generic procedure, there shall be no return_statements that apply to that procedure.
Static Semantics
If a pragma No_Return applies to a generic procedure, pragma No_Return applies to all instances of that generic procedure.
Dynamic Semantics
If a pragma No_Return applies to a procedure, then the exception Program_Error is raised at the point of the call of the procedure if the procedure body completes normally.
!corrigendum 11.4.1(4)
Replace the paragraph:
procedure Raise_Exception(E : in Exception_Id; Message : in String := ""); function Exception_Message(X : Exception_Occurrence) return String; procedure Reraise_Occurrence(X : in Exception_Occurrence);
by:
procedure Raise_Exception(E : in Exception_Id; Message : in String := ""); pragma No_Return(Raise_Exception); function Exception_Message(X : Exception_Occurrence) return String; procedure Reraise_Occurrence(X : in Exception_Occurrence);
!corrigendum 11.4.1(14)
Replace the paragraph:
Raise_Exception and Reraise_Occurrence have no effect in the case of Null_Id or Null_Occurrence. Exception_Message, Exception_Identity, Exception_Name, and Exception_Information raise Constraint_Error for a Null_Id or Null_Occurrence.
by:
Reraise_Occurrence has no effect in the case of Null_Occurrence. Raise_Exception, Exception_Message, Exception_Identity, Exception_Name, and Exception_Information raise Constraint_Error for a Null_Id or Null_Occurrence.
!ACATS test
Create an ACATS C-Test to check that a procedure with No_Return raises Program_Error if it reaches the end of the body. Create an ACATS B-Test to check that explicit return statements are illegal in a No_Return procedure. Create an ACATS C-Test to check that an instance of a generic procedure with No_Return raises Program_Error if it reaches the end of the body.
!appendix

From: Tucker Taft
Sent: Tuesday, March 4, 2003  11:13 AM

Here is an amendment AI on pragma No_Return,
a pragma supported by GNAT and which we have recently
added to AdaMagic to eliminate various spurious
warnings.

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

From: Robert I. Eachus
Sent: Tuesday, March 4, 2003  2:46 PM

> Here is an amendment AI on pragma No_Return,  a pragma supported by
> GNAT and which we have recently
> added to AdaMagic to eliminate various spurious warnings.

Should this be referred to as the MTA amendment? ;-)

For non-Americans, the song that made the Kingston Trio famous over 40
years ago was The MTA.  ("But did he ever return?  No he never
returned--poor old Charlie--and his fate is still unlearned.  He may
ride forever 'neath the streets of Boston.  He's the man who never
returned.)

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

From: Robert A Duff
Sent: Tuesday, March 4, 2003  3:43 PM

Thanks for that amusing bit of nostalgia.

I'm told the point was that the subway required paying on the way out.
Charlie didn't have the money (or the token?), so he had to ride
forever, 'neath the streets of Boston.  His wife handed him sandwiches
on the way past the station, but for some reason never gave him the
money to get out.

The current subway in Boston requires paying on the way in.

- Bob

P.S. For symmetry, we should have a pragma No_Deposit.

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

From: Robert I. Eachus
Sent: Tuesday, March 4, 2003  6:41 PM

Touch‚!  I guess that would be for functions that didn't put their
return values on the stack. ;-)

Also off topic, yes, the "one more nickel" was to be paid on exit if you
transferred.  But the normal fare would be paid on entry.  Haven't
gotten off at Park Street Under to switch to a trolley in decades.

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

From: Robert Dewar
Sent: Tuesday, March 4, 2003  2:39 PM

> Additional option: Add Always_Raise_Exception
> and Always_Reraise_Occurrence to Ada.Exceptions
> (or perhaps a child?) to which pragma No_Return would
> apply.  These would raise Constraint_Error if given
> Null_Id or Null_Occurrence, respectively, like several
> of the other routines in Ada.Exceptions.
>
> Alternatively, create a "Ada.Exceptions.No_Return" child
> and add no-return versions of Raise_Exception and
> Reraise_Occurrence there.

As a side note, what GNAT does is to specialize the warning messages involved,
and never complain about a dubious return if the name of the function is
Raise_Exception. A bit of a kludge .... :-)

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

From: Robert A. Duff
Sent: Tuesday, March 4, 2003  3:30 PM

> As a side note, what GNAT does is to specialize the warning messages
> involved, and never complain about a dubious return if the name of the
> function is Raise_Exception.  A bit of a kludge .... :-)

Makes perfect sense.  A kludge to get around what is arguably a language
design flaw.  Indeed, Robert has so-argued, and I think today Tucker
would agree that Raise_Exception ought to raise an exception (always),
and if we need one that ignores null it should have been called
Maybe_Raise_Exception, or some such thing.  Too late.

But it's interesting that you chose not to put a pragma No_Return on
Raise_Exception (and suppress whatever error message that causes in the
body).

Pragma No_Return really means no return, provably at compile time, so a
compiler can legitimately remove dead code after such a call -- such as
the implicit "raise Program_Error;" at the end of a function body.

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

From: Robert Dewar
Sent: Tuesday, March 4, 2003  4:07 PM

> But it's interesting that you chose not to put a pragma No_Return on
> Raise_Exception (and suppress whatever error message that causes in the
> body).

Because that would cause invalid code to be generated! No_Return does much
more than suppress error messages for us, it cuts branches in the flow graph,
and the optimizer can and does take advantage of this.

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

From: Robert A. Duff
Sent: Tuesday, March 4, 2003  4:19 PM

Right, that was exactly my point.  Our optimizer does the same
(i.e. believe that pragma No_Return is the truth).

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

From: Robert I. Eachus
Sent: Tuesday, March 4, 2003  2:39 PM

Count me definitely in favor.

> With this pragma, it would be nice to be able to apply it to
> Ada.Exceptions.Raise_Exception and Reraise_Occurrence However, these
> existing procedures have no effect if given Null_Id or
> Null_Occurrence, respectively.

> It might be desirable to change this, but upward compatibility argues
> for defining new procedures.

I think in this case that the officially upwardly incompatible change is
by far the best option.  I can't imagine any program outside compiler
test suites that depends on this behavion.

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

From: Tucker Taft
Sent: Tuesday, March 4, 2003  3:42 PM

Robert I. Eachus wrote:
> Count me definitely in favor.

Glad to hear it.

> I think in this case that the officially upwardly incompatible change is
> by far the best option.  I can't imagine any program outside compiler
> test suites that depends on this behavion.

I guess I agree for Raise_Exception.  For Reraise_Occurrence,
it seems that one might have an exception handler that if
executed, uses Save_Occurrence to save away the occurrence,
and then the enclosing subprogram ends with a Reraise_Occurrence,
which returns normally if no exception occurrence has been saved away.

Raise_Exception is the important one, in any case, from
a "typical user" perspective.

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

From: Robert Dewar
Sent: Tuesday, March 4, 2003  3:52 PM

> I think in this case that the officially upwardly incompatible change is
> by far the best option.  I can't imagine any program outside compiler
> test suites that depends on this behavion.

I tend to agree, and if you make the semantics be that Program_Error is raised
if presented with a null occurrence, it is unlikely that this upward
incompatibility will cause any trouble.

P.S. to me this was a small but really nasty design error in the current spec.

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

From: Randy Brukardt
Sent: Tuesday, March 4, 2003  4:15 PM

I certainly prefer that to adding "almost the same" routines. Moreover, we
had a similar problem with this package (AI-241), and we opted for the
incompatibility rather than adding new routines. So it seems reasonable to
adopt the same rule here.

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

From: Tucker Taft
Sent: Wednesday, March 5, 2003  8:06 AM

I would rather leave Reraise_Occurrence as is, since
I don't think that affects users, and an upward
compatibility issue is at least somewhat easier to
construct for that one.

But Raise_Exception with a Null_Id seems very
obscure.  I would (mildly) recommend Constraint_Error
rather than Program_Error, to be consistent with
the other routines.

By just changing one routine, there is a nice
"conservation of Constraint_Error" because we have
proposed that Exception_Id(Null_Occurrence) will now *not*
raise Constraint_Error, while Raise_Exception(Null_Id)
*will* raise Constraint_Error.  ;-)

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

From: Robert Dewar
Sent: Wednesday, March 5, 2003  2:24 PM

I agree with all this (including the smiley)

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

From: Jean-Pierre Rosen
Sent: Wednesday, March 5, 2003  1:43 PM

> I think in this case that the officially upwardly incompatible change is
> by far the best option.  I can't imagine any program outside compiler
> test suites that depends on this behavion.
>
Lack of imagination? ;-)
I certainly have programs that depend on it.
The idea is that at a certain point, you detect an exception but you don't want
it to be propagated yet. You catch it and save it. Then later, you do a
Reraise_Occurrence. If there was no exception,  nothing happens.

Note you can easily add an "if" to check for Null_ID, but *not* for
Null_Occurrence.

(for this reason and others, it would be nice to add an "Is_Null_Occurrence" to
Ada.exceptions).

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

From: Robert Dewar
Sent: Wednesday, March 5, 2003  2:40 PM

Note that JPR's example uses Reraise_Occurrence, confirming Tuck's view that we
should not change this one, only the raise call.

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

From: Tucker Taft
Sent: Wednesday, March 5, 2003  2:48 PM

This reply seems to back up the idea of leaving
Reraise_Occurrence as it is now, and only changing
Raise_Exception to be a "No_Return" procedure.

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

From: Robert I. Eachus
Sent: Wednesday, March 5, 2003  3:57 PM

This is looking like a consensus.  I find the examples somewhat
contrived, but I find it even harder to find an example where a compiler
can generate more efficient code for a Reraise_Occurrence if it is
guarenteed to raise some exception.  On the other hand, calling
Raise_Exception to NOT raise an exception is baroque.

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

From: Randy Brukardt
Sent: Wednesday, March 5, 2003  4:10 PM

Jean-Pierre said:
> Note you can easily add an "if" to check for Null_ID, but *not* for
> Null_Occurrence.
> (for this reason and others, it would be nice to add an
> "Is_Null_Occurrence" to Ada.exceptions).

That was the point of AI-241 (approved long ago). Exception_Identity does
not raise Constraint_Error, it returns Null_Id. So:

   if Ada.Exceptions.Exception_Identity (My_Occurrence) = Null_Id then

works to test for Null_Occurrence. And *that* is the existing
incompatibility that we were discussing, which is why introducing another
one in the same package isn't bad.

Of course, if there is any real use of the construct in question, its best
not to change it. So I tend to agree with the consensus here.

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

From: Robert Dewar
Sent: Wednesday, March 5, 2003  4:36 PM

I must say that I find any code that uses Reraise_Occurrence relying on the
null case behavior to be very bad programming style. I would far rather
see an explicit test at the source level

   if x /= Null_Occurrence then
      Reraise_Occurrence (X);
   end if;

I must say that from a design point of view it is very odd to have inconsistent
behavior for the two routines. I vote for "fixing" them both, even if it does
make a minor upwards incompatibility.

In the GNAT version of a-except.ads we have:

   procedure Raise_Exception (E : Exception_Id; Message : String := "");
   --  Note: it would be really nice to give a pragma No_Return for this
   --  procedure, but it would be wrong, since Raise_Exception does return
   --  if given the null exception. However we do special case the name in
   --  the test in the compiler for issuing a warning for a missing return
   --  after this call. Program_Error seems reasonable enough in such a case.
   --  See also the routine Raise_Exception_Always in the private part.

   function Exception_Message (X : Exception_Occurrence) return String;

   procedure Reraise_Occurrence (X : Exception_Occurrence);
   --  Note: it would be really nice to give a pragma No_Return for this
   --  procedure, but it would be wrong, since Reraise_Occurrence does return
   --  if the argument is the null exception occurrence. See also procedure
   --  Reraise_Occurrence_Always in the private part of this package.


:-)

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

From: Jean-Pierre Rosen
Sent: Thursday, March 6, 2003  2:41 AM

Agreed, BUT an occurrence is a limited type....
I agree with the consensus, provided:
1) either Reraise_Occurrence is left as is
2) or we provide "=" for occurrences.

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

From: Robert Dewar
Sent: Thursday, March 6, 2003  7:45 AM

Well in fact didn't we agree to provide a test for null occurrence, so the code I
wrote conceptually as:

> >    if x /= Null_Occurrence then
> >       Reraise_Occurrence (X);
> >    end if;

actually comes out as

    if not Is_Null_Occurrence (X) then
	Reraise_Occurrence (X);
    end if;

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

From: Tucker Taft
Sent: Thursday, March 6, 2003  8:10 AM

An AI already approved allows Exception_Id(occurrence)
to be used to check for null occurrences:

    if Exceptions.Exception_Id(X) /= Exceptions.Null_Id then
        Exceptions.Reraise_Occurrence(X);
    end if;

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

From: Robert A Duff
Sent: Tuesday, March 18, 2003  6:09 PM

Question about pragma No_Return: What does it mean when a call is
dispatching?  What does GNAT do in this case?

Similar question for a call through an access-to-subp.  Can pragma
No_Return be applied to an access-to-subp type?

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

From: Gary Dismukes
Sent: Tuesday, March 18, 2003  6:55 PM

> Question about pragma No_Return: What does it mean when a call is
> dispatching?  What does GNAT do in this case?

GNAT just applies the pragma on a procedure-by-procedure basis.
It doesn't treat dispatching procedures specially.  So a dispatching
call must be assumed to return.

> Similar question for a call through an access-to-subp.  Can pragma
> No_Return be applied to an access-to-subp type?

GNAT only allows it for procedures.

I guess it would be reasonable to support it for access-to-subp
types, and require that the pragma apply to the prefix of 'Access
if it applies to the expected access type.  So calls via an access
value of such a type could be assumed to never return.  Not sure
how useful that would be though.

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

From: Robert I. Eachus
Sent: Sunday, February 29, 2004  11:32 AM

Tucker Taft wrote:

> This version of AI-329 on pragma No_Return has
> wording, and specifies that Ada.Exceptions.Raise_Exception
> is No_Return. [Editor's note: That is version /02.]

I really like the AI as written.  If the upward incompatibility gets
voted down I prefer this alternative:

>   package Ada.Exceptions.No_Return is
>        procedure Raise_Exception( ... );
>        procedure Reraise_Occurrence( ... );
>   end Ada.Exceptions.No_Return;
>
Another option might be to do the incompatible change but provide a
package Ada.Exceptions.Conditional that keeps the current behavior.  (Or
even call it Ada.ExceptionsPossibly_Return. ;-)  Users wh really need
the current behavior can use a one-line if statement as a wrapper  And
that if makes it explicit that the programmer is mixing both return and
no return behavior.

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

From: Arnaud Charlet
Sent: Monday, March  1, 2004  8:43 AM

A minor comment: GNAT already defines for internal
usage (in the private part since it's not yet part of the RM) the procedures
Raise_Exception_Always and Reraise_Occurrence_Always.

Are there any reasons to prefer Always_xxx rather than xxx_Always ?

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

From: Robert Dewar
Sent: Monday, March  1, 2004  5:13 PM

I prefer the suffix forms, since then they alphebetize in a consistent
manner.

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

From: Robert Dewar
Sent: Monday, March  1, 2004 6:31 PM

I am inclined to bite the bullet and accept the incompatibility
here. I suspect that programs that would be affected may well
have a bug anyway :-)

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

From: Tucker Taft
Sent: Monday, March  1, 2004  7:42 PM

Sorry, I realize the summary/proposal were not
updated to correspond to the wording section.
The wording has been defined to make Raise_Exception
always raise an exception, and to leave Reraise_Occurrence
as it is.  This seemed to be the consensus of the
review last time, if I remembered it correctly.

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

From: Randy Brukardt
Sent: Monday, March  1, 2004  7:42 PM

That's the way I remembered it. We decided to have the (slight)
incompatibility.

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

From: Randy Brukardt
Sent: Monday, March  1, 2004  8:04 PM

No problem, I just posted version /03 that solves this problem.

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

From: Robert Dewar
Sent: Thursday, December  8, 2005  11:45 AM

For the record, we already implemented this as
described, namely maintaining a difference between
Ada 95 behavior (returns silently) and Ada 2005
behavior (raises CE) when passed a null Exception_Id,
but again, I would prefer to see Ada 95 compilers
be allowed to adopt the Ada 2005 behavior (in the
same way we allowed Ada 83 compilers to adopt the
8-bit characters of Ada 95).

Either this is a trivial incompatibility, in which
case why insist on it, or it is not, in which case
it is a gratuitous non-upwards compatible change.

It seems to me that insisting on different behavior
in Ada 95 and Ada 2005 is trying to have it both ways.

P.S. by the way, one of the reasons I think it is very
important to be able to handle Ada 95 and Ada 2005 with
a common run time is that for the forseeable future I
envision mixed applications, with some units compiled
in Ada 95 mode and some in Ada 2005 mode.

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

From: Tucker Taft
Sent: Thursday, December  8, 2005  1:51 PM

I guess this is another case where I would stick
with the "Ada 95 is Ada 95" view, and have some
kind of configuration pragma to request Ada 2005
semantics for things like this.  If you believe
mixed systems are likely, then you might want
to make this the default for your customers,
but I wouldn't expect other vendors to necessarily
make the same decision about the "default" mode.

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

From: Robert Dewar
Sent: Thursday, December  8, 2005  3:17 PM

Well that is of course what we do, but once again
if the view is that the semantics in this case are
significantly different enough to worry about in this
way, then I think it is totally unjustified to have
introduced this gratuitous non-upwards compatibility.

The only acceptable argument for a non-upwards
compatibility is that you convince yourself that
no Ada 95 program will run into the problem. But
if that is the case, why worry about how Ada 95
programs treat the situation.

If you think the Ada 95 decision was a mistake, then
sure, correct it, but that should be a correction to
Ada 95 (we have plenty of those :-)

And by the way, this particular case is not hard to
implement with zero overhead at run time, and a common
library for the two modes (that's absolutely essential,
and so far we have not had to compromise that
requirement, though we have had to do some fiddling,
as in this case).

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

From: Randy Brukardt
Sent: Thursday, December  8, 2005  2:25 PM

I disagree with Tucker, for the simple reason that the AI with this change
(AI-241) is classified as a Binding Interpretation. It is *intended* to
apply to Ada 95. Indeed, the ACATS tests were changed to not require either
behavior years ago.

The AI was originally written up as an Amendment, but it was changed to a
Binding Interpretation at a meeting (November 2000). That implies that we
considered whether it should apply to Ada 95, and decided it should apply to
Ada 95. (The minutes unfortunately do not record the discussion that leads
up to changing the status.) Surely we didn't change the status just to make
more work for the editor!

Ergo, there is no issue here -- what Robert wants is in fact the correct
interpretation. (Indeed, when Robert asked the very same question back in
May, he got the very same answer from me.)

There won't be an ACATS test insisting on the change for Ada 95 (because of
the WG 9 resolution), but there is no test that requires the old behavior,
either. (And if any are found, it would be quickly repaired.)

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

From: Tucker Taft
Sent: Thursday, December  8, 2005  2:35 PM

Given this (which I suppose I should have known!), I disagree
with Tucker too!  If it is a BI, then it *is* Ada 95.

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

From: Robert Dewar
Sent: Thursday, December  8, 2005  3:21 PM

> I disagree with Tucker, for the simple reason that the AI with this change
> (AI-241) is classified as a Binding Interpretation. It is *intended* to
> apply to Ada 95. Indeed, the ACATS tests were changed to not require either
> behavior years ago.

Ah ha! What is confusing here is that this change is also written
up in AI-329. Probably it does not belong there???

OK, I will remove the "and then Ada_Version >= Ada_2005" from our code :-)

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

From: Robert Dewar
Sent: Thursday, December  8, 2005  3:56 PM

I am confused, AI-241 is about testing for null occurrences, it does not
change the semantics of Raise_Exception with a null exception_id value
which is what we are talking about here. Randy???

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

From: Randy Brukardt
Sent: Thursday, December  8, 2005  4:29 PM

My bad; I read "Raise_Exception" as "Raise_Occurrence". I suppose I should
have actually read your subject line (it was truncated in my mailer).

Anyway, I agree with you that this is another AI that is misclassified. Or
more accurately, part of it is misclassified. It's silly that we have made a
significant, incompatible change in this paragraph that applies to Ada 95,
and yet another change that is far less likely to be incompatible in
practice in the same paragraph is not supposed to apply to Ada 95.

I'm reluctantly coming to the conclusion that anything short of a complete
fork in technology (as we did for Ada 95 from Ada 83) is probably going to
be impractical. There's just too many tiny differences, and clearly there is
no will to reconcile them. (Our Ada 95 compiler has an Ada 83 switch, but it
only provides "easy" compatibility; it doesn't try to undo the complex
resolution changes, for instance. If you need perfect Ada 83 compatibility,
we still offer a separate Ada 83 product. I wanted to avoid that this time,
but it is not looking practical.) And I think that truly mixed programs
won't really be possible (nor are they that likely to be necessary, as was
the case with Ada 83).

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

From: Robert Dewar
Sent: Thursday, December  8, 2005  4:32 PM

> Anyway, I agree with you that this is another AI that is misclassified. Or
> more accurately, part of it is misclassified. It's silly that we have made a
> significant, incompatible change in this paragraph that applies to Ada 95,
> and yet another change that is far less likely to be incompatible in
> practice in the same paragraph is not supposed to apply to Ada 95.

Yes, that's what I think, but no big deal, it was easy enough to accomodate
without any big palava. What we do is to have the compiler recognize calls
to this procedure (easy to do in our environment), and append a raise after
the call if operating in Ada 2005 mode.

> I'm reluctantly coming to the conclusion that anything short of a complete
> fork in technology (as we did for Ada 95 from Ada 83) is probably going to
> be impractical. There's just too many tiny differences, and clearly there is
> no will to reconcile them. (Our Ada 95 compiler has an Ada 83 switch, but it
> only provides "easy" compatibility; it doesn't try to undo the complex
> resolution changes, for instance. If you need perfect Ada 83 compatibility,
> we still offer a separate Ada 83 product. I wanted to avoid that this time,
> but it is not looking practical.) And I think that truly mixed programs
> won't really be possible (nor are they that likely to be necessary, as was
> the case with Ada 83).

Well we have implemented over two thirds of the Ada 2005 AI's, including
almost all the big hard ones. And we have not come to this conclusion, we
have managed to keep everything unified.

We do have a few tricks, such as

pragma Preelaborate_05;

allowed only in the library, which says you are preelaborate if the
program withing the library is in Ada 2005 mode, and otherwise you
are not preelaborate. A bit of a kludge, but manageable.

Neither of the issues I raised are blocking for us, but I do find it
irritating to introduce incompatibilities, and take the attitude that
it is just fine for people who want to move to Ada 2005 to face these
but not fine for people using Ada 95. As I said a few times before,
we took EXACTLY the opposite view when we allowed Ada 83 compilers
to implement 8-bit characters.

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

From: Randy Brukardt
Sent: Thursday, December  8, 2005  11:57 PM

> Yes, that's what I think, but no big deal, it was easy enough to accomodate
> without any big palava. What we do is to have the compiler recognize calls
> to this procedure (easy to do in our environment), and append a raise after
> the call if operating in Ada 2005 mode.

Humm. That certainly would work, but wouldn't that cause trouble for
implementing No_Return? The routine would raise Program_Error instead of
Constraint_Error (a No_Return procedure that returns raises Program_Error).
(Easily fixed by putting the raise conditionally before the routine, or
eliminating the check if it is done at the point of the call.)

(In our compiler, this is probably about the same as yours. Ada.Exceptions
is a built-in package, so the compiler knows about the routine; that means
no problem with No_Return (we can assume that it is OK and not include the
check), and it can generate a raise rather than a skip if it is Null_Id.)

> > I'm reluctantly coming to the conclusion that anything short of a complete
> > fork in technology (as we did for Ada 95 from Ada 83) is probably going to
> > be impractical. There's just too many tiny differences, and clearly there
> > is no will to reconcile them. (Our Ada 95 compiler has an Ada 83 switch,
> > but it only provides "easy" compatibility; it doesn't try to undo the
> > complex resolution changes, for instance. If you need perfect Ada 83
> > compatibility, we still offer a separate Ada 83 product. I wanted to
> > avoid that this time, but it is not looking practical.) And I think
> > that truly mixed programs won't really be possible (nor are they
> > that likely to be necessary, as was the case with Ada 83).
>
> Well we have implemented over two thirds of the Ada 2005 AI's, including
> almost all the big hard ones. And we have not come to this conclusion, we
> have managed to keep everything unified.

Well, everybody's compilers are different. There just are so many
interactions between things that trying to get them all perfect seems
horrible. Adding a mechanism to make things "disappear" from the symbol
table, for instance, is a multiday job, especially because a pragma would be
very hard to make work (it would be too late to find the appropriate item).

I'm sure it is possible to do (because pretty much anything is possible with
enough work), but I'm wondering if starting with a clean slate would be
better. I don't want to be spending lots of time inventing compatibility
features rather than actually implementing useful stuff.

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

From: Robert Dewar
Sent: Friday, December  9, 2005  7:02 AM

> Humm. That certainly would work, but wouldn't that cause trouble for
> implementing No_Return? The routine would raise Program_Error instead of
> Constraint_Error (a No_Return procedure that returns raises Program_Error).
> (Easily fixed by putting the raise conditionally before the routine, or
> eliminating the check if it is done at the point of the call.)

No, we don't mark this routine as No_Return, since it already has to be
specially handled wrt No_Return in Ada 95 mode, and that same circuitry
works fine in Ada 2005.

> (In our compiler, this is probably about the same as yours. Ada.Exceptions
> is a built-in package, so the compiler knows about the routine; that means
> no problem with No_Return (we can assume that it is OK and not include the
> check), and it can generate a raise rather than a skip if it is Null_Id.)

Right, similar to what I describe above

> Well, everybody's compilers are different. There just are so many
> interactions between things that trying to get them all perfect seems
> horrible. Adding a mechanism to make things "disappear" from the symbol
> table, for instance, is a multiday job, especially because a pragma would be
> very hard to make work (it would be too late to find the appropriate item).
>
> I'm sure it is possible to do (because pretty much anything is possible with
> enough work), but I'm wondering if starting with a clean slate would be
> better. I don't want to be spending lots of time inventing compatibility
> features rather than actually implementing useful stuff.

For us, this has been a minimal issue, the only times that it has seemed
even a vague annoyance are the ones I brought to the attention of this
list (by far the worst for us is the Wide_Wide stuff in Ada.Exceptions,
but the mechanism we are adding for that, pragma Implicit_Child, will
allow cleanups in the way we handle the implicit children of Text_IO
in any case). And a fork would be FAR more work to deal with in terms
of qualifying production compilers for dozens of targets.

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

From: Pascal Leroy
Sent: Friday, December  9, 2005  4:12 AM

> I would prefer to see Ada 95 compilers
> be allowed to adopt the Ada 2005 behavior

As we said at the last ARG meeting, we have to consider these issues on a
case-by-case basis.  In this particular instance I tend to agree with
Robert.  Passing a Null_Id to Raise_Exception is probably a bug anyway (no
reason why anyone would do that) so raising C_E is actually helpful.

Yes, it is unfortunate that this is entangled with the other AI 329
changes, but that's life.

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

From: Robert Dewar
Sent: Friday, December  9, 2005  7:14 AM

OK, so let's see if we can get a consensus on this, because it would
be a nice cleanup (even though it would be extra work at this stage,
since I already implemented the kludge to get different behavior in
the two cases).

By the way, it is not clear to me if the C_E gets raised with the
given message, or an implementation dependent message (I have taken
the latter view so far, which seems reasonable to me!)

> Yes, it is unfortunate that this is entangled with the other AI 329
> changes, but that's life.

Indeed :-)

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

From: Tucker Taft
Sent: Friday, December  9, 2005  7:54 AM

> As we said at the last ARG meeting, we have to consider these issues on a
> case-by-case basis.  In this particular instance I tend to agree with
> Robert.  Passing a Null_Id to Raise_Exception is probably a bug anyway (no
> reason why anyone would do that) so raising C_E is actually helpful.

I hate to be a curmudgeon on this, but I can see some cases where
it would be intentional.  For example (and this approximates some
code we have in our run-time system), you have some cleanup that
you want to do at the end of a routine under all circumstances,
and then either return or raise an exception to report status
to the caller.  It seems pretty reasonable to store away an exception
ID that represents the final status of the routine, then do the
cleanup, and then pass this ID to Raise_Exception, and then return.
If the ID is Null_Id, then Raise_Exception does nothing, and so
you end up just returning.  If ID is not Null_Id, then an exception
is raised, and the return is bypassed.

I can particularly see this when you create an Ada wrapper for a "C"
routine, where you have some kind of status return from the C routine,
you use that to decide whether to raise an exception or return
normally, you save away your decision, you then clean up the various
data structures you created to call the C routine (e.g. null-terminated
strings, etc.), and then call Raise_Exception followed by return.

For someone who has decided to start the transition to Ada 2005,
I would assume that they would do some kind of systematic review
of these kind of issues as part of that process.  For someone who
is sticking with Ada 95, I have trouble understanding why the
semantics of this should change.

You could say that if I believe the above, then why change the
semantics in Ada 2005.  But I think the decision process is
somewhat different.  For Ada 2005, we want the resulting language
to be self-consistent, not look like a language with some new
features bolted on.  We are willing to accept some degree of
upward incompatibility, if we think there are easy workarounds,
and the problems will show up at compile-time or with an exception
at run-time.  I don't see why those decisions should affect folks
who are sticking with Ada 95, or at least not until they choose
to move up to a compiler that uses Ada 2005 semantics where there
is a conflict (presumably to get a jump on the ultimate transition).

> Yes, it is unfortunate that this is entangled with the other AI 329
> changes, but that's life.

This seems like *not* something that could be considered
a Binding Interpretation, even if it were all by itself as
a separate AI.  The existing semantics are well-defined, and
even potentially useful under certain circumstances.  We
made the decision for Ada 2005 that the existing semantics
were error prone, but that is for new code.  Presumably for
existing code, the error-prone-ness has already been dealt with.

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

From: Robert Dewar
Sent: Friday, December  9, 2005 12:28 PM

> I hate to be a curmudgeon on this, but I can see some cases where
> it would be intentional.  For example (and this approximates some
> code we have in our run-time system), you have some cleanup that
> you want to do at the end of a routine under all circumstances,
> and then either return or raise an exception to report status
> to the caller.  It seems pretty reasonable to store away an exception
> ID that represents the final status of the routine, then do the
> cleanup, and then pass this ID to Raise_Exception, and then return.
> If the ID is Null_Id, then Raise_Exception does nothing, and so
> you end up just returning.  If ID is not Null_Id, then an exception
> is raised, and the return is bypassed.

If you believe this then you should NEVER have countenanced
this gratuitous non-upwards compatibility

> For someone who has decided to start the transition to Ada 2005,
> I would assume that they would do some kind of systematic review
> of these kind of issues as part of that process.  For someone who
> is sticking with Ada 95, I have trouble understanding why the
> semantics of this should change.

You must live in another world, and one which would entirely
prevent ANY of our serious customers moving to Ada 2005. A
systematic review of millions of lines of code is simply out
of the question. If this requirement had been true of Ada 95
it would have been the case that even fewer users would have
made the transition to Ada 95 (as you know many still have not
made this transition).

> You could say that if I believe the above, then why change the
> semantics in Ada 2005.  But I think the decision process is
> somewhat different.  For Ada 2005, we want the resulting language
> to be self-consistent, not look like a language with some new
> features bolted on.  We are willing to accept some degree of
> upward incompatibility, if we think there are easy workarounds,
> and the problems will show up at compile-time or with an exception
> at run-time.  I don't see why those decisions should affect folks
> who are sticking with Ada 95, or at least not until they choose
> to move up to a compiler that uses Ada 2005 semantics where there
> is a conflict (presumably to get a jump on the ultimate transition).

Of course such an argument may be valid in some cases, although the
burden for me is very very high, and I see nothing in Ada 2005 that
warrants an exception to the principle of no upwards incompatibility
(I would have handled NOT NULL differently for instance), but the idea
that it applies to Raise_Exception seems very dubious to me.

After all, this is not causing any major issues now, Ada 95 users
and vendors have lived with this for a decade, and it is not even
on the radar screen as a significant problem
>
>> Yes, it is unfortunate that this is entangled with the other AI 329
>> changes, but that's life.
>
> This seems like *not* something that could be considered
> a Binding Interpretation, even if it were all by itself as
> a separate AI.  The existing semantics are well-defined, and
> even potentially useful under certain circumstances.  We
> made the decision for Ada 2005 that the existing semantics
> were error prone, but that is for new code.  Presumably for
> existing code, the error-prone-ness has already been dealt with.

I doubt it, are you really saying that you think all big systems
are error free?

Once again I am not arguing from the point of view of implementation
simplicity here. Indeed if the ARG were to follow the suggestion of
allowing back porting, it would be a pain in the neck, since I would
have to undo what has already been done, test again, refile tests,
worry about getting rid of the garbage ACATS test etc. However, I
would do that if I could, just so that the situation with users in
dealing with incompatibilities were clearer.

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

From: Randy Brukardt
Sent: Friday, December  9, 2005  1:05 PM

> This seems like *not* something that could be considered
> a Binding Interpretation, even if it were all by itself as
> a separate AI.  The existing semantics are well-defined, and
> even potentially useful under certain circumstances.  We
> made the decision for Ada 2005 that the existing semantics
> were error prone, but that is for new code.  Presumably for
> existing code, the error-prone-ness has already been dealt with.

If that's true, then AI-241 should not have been classified a BI. Because
the same holds true there. In that case, the semantics aren't particularly
useful, but we agreed that some programs might depend on those semantics
simply because that was the only way to make the test. So, if anything, I
think the AI-241 change is more likely in practice.

My objection here is that we have two changes, similar in degree, in the
*same* paragraph, and yet one is a BI requiring changes in Ada 95, and the
other is an Amendment not even allowing the change in Ada 95. Does this
strike anyone else as inconsistent???

So I say, let's reclassify this one (this part of this one) as a BI.

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

From: Pascal Leroy
Sent: Saturday, December 10, 2005  4:50 AM

Yes, it surely is inconsistent.

I am open-minded and could be convinced by Tuck's argument (after all, the
severity of incompatibilities is a judgment call) but then he should
surely insist to reclassify AI 241 as an Amendment.

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

From: Jean-Pierre Rosen
Sent: Monday, December 12, 2005  3:02 AM

> I hate to be a curmudgeon on this, but I can see some cases where
> it would be intentional.  For example (and this approximates some
> code we have in our run-time system), you have some cleanup that
> you want to do at the end of a routine under all circumstances,
> and then either return or raise an exception to report status
> to the caller.  It seems pretty reasonable to store away an exception
> ID that represents the final status of the routine, then do the
> cleanup, and then pass this ID to Raise_Exception, and then return.
> If the ID is Null_Id, then Raise_Exception does nothing, and so
> you end up just returning.  If ID is not Null_Id, then an exception
> is raised, and the return is bypassed.

I think this issue was discussed, and the feeling was that if you do
this, you are much better off saving the *occurrence* and reraising the
occurrence. And reraising Null_Occurrence still does nothing.

But reraising through the Exception_ID seemed very unlikely.

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

From: John Barnes
Sent: Monday, December 12, 2005  2:08 AM

I thought 241 was reclassified as an amendment. I discuss it in the
rationale as if it were an amendment.

Maybe we agreed to reclassify it but didn't actually do it.

If so just reclassify it if that solves the problem.

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

From: Randy Brukardt
Sent: Monday, December 12, 2005  12:57 PM

> I thought 241 was reclassified as an amendment. I discuss it in the
> rationale as if it were an amendment.

That's backwards. It originally was an Amendment, and we decided to
reclassify it as a Binding Interpretation. You probably never noticed that
and failed to make that change in the Rationale.

> Maybe we agreed to reclassify it but didn't actually do it.
>
> If so just reclassify it if that solves the problem.

Well, reversing a carefully considered decision (either of them) requires
more careful consideration. I'd be in favor of reclassifying the portion of
AI-329 relating to Raise_Exception as a Binding Interpretation. As
Jean-Pierre points out, we carefully considered compatibility and decided it
wasn't a real issue.

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


Questions? Ask the ACAA Technical Agent