Version 1.4 of ais/ai-00414.txt

Unformatted version of ais/ai-00414.txt version 1.4
Other versions for file ais/ai-00414.txt

!standard 6.05.01 (01)          05-03-09 AI95-00414/02
!class amendment 05-02-02
!status Amendment 200Y 05-03-09
!status ARG Approved 8-0-2 05-02-12
!status work item 05-02-02
!status received 05-02-02
!priority Medium
!difficulty Easy
!subject pragma No_Return for overriding procedures
!summary
This AI corrects some problems with AI-00329/06, which defines pragma No_Return.
!problem
The goal of pragma No_Return is to ensure that a call to a No_Return procedure will not return normally. The main problem with AI-00329 is that there is no such assurance in the case of a dispatching call. The other problems are nitpicks; they are mentioned in the discussion.
!proposal
We ensure that dispatching calls work properly by requiring pragma No_Return on a procedure that overrides a dispatching No_Return procedure.
!wording
AI-00329 adds a new clause, as follows:
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.
[End of old wording from AI-00329.]
----------------
This AI replaces 6.5.1 with the following:
6.5.1 Pragma No_Return
A pragma No_Return indicates that a procedure cannot return normally[; it may propagate an exception or loop forever].
Syntax
The form of a pragma No_Return, which is a representation pragma (see 13.1), is as follows:
pragma No_Return(procedure_local_name {, procedure_local_name});
Legality Rules
Each procedure_local_name shall denote one or more procedures or generic procedures; the denoted entities are "non-returning". The procedure_local_name shall not denote a null procedure nor an instance of a generic unit.
AARM Reason: A null procedure cannot have the appropriate non-returning semantics, as it does not raise an exception or loop forever.
AARM Ramification: The procedure can be abstract. The denoted declaration can be a renaming_declaration if it obeys the usual rules for representation pragmas: the renaming has to occur immediately within the same declarative_region as the renamed subprogram. If non-returning procedure is renamed (anywhere) calls through the new name still have the non-returning semantics.
A return_statement shall not apply to a non-returning procedure or generic procedure.
A procedure shall be non-returning if it overrides a dispatching non-returning procedure. In addition to the places where Legality Rules normally apply (see 12.3), this rule applies also in the private part of an instance of a generic unit.
AARM Reason: This ensures that dispatching calls to non-returning procedures will, in fact, not return.
If a renaming-as-body completes a non-returning procedure declaration, then the renamed procedure shall be non-returning.
Static Semantics
If a generic procedure is non-returning, then so are its instances. If a procedure declared within a generic unit is non-returning, then so are the corresponding copies of that procedure in instances.
Dynamic Semantics
If the body of a non-returning procedure completes normally, Program_Error is raised at the point of the call.
Note: AI-00329 also modifies 11.4.1; this AI retains those modifications as is.
AARM Discussion:
The primary goal of pragma No_Return is to document the fact that calls will not return normally. An example is a procedure that logs an error and then unconditionally raises an exception. Another example is a procedure that deliberately enters an infinite loop. Non-returning procedures are rare, so it is useful to document this unusual case. However, they are called often. This capability is useful for three reasons:
1. Programmers can better understand programs that have this unusual
control-flow structure.
2. Compilers can use this control-flow information to generate better warnings.
The pragma essentially removes certain control-flow arcs from the compiler's control-flow graph.
A compiler can warn if it is unable to prove that the end of the procedure body is unreachable. A compiler can warn about code following a call to a non-returning procedure; it's dead code. Most importantly, a compiler can avoid warning in cases like this:
if ... then
Fatal_Error("..."); -- non-returning
else
X := ...; -- initialize X
end if; ... X ... -- no warning
Without pragma No_Return, the compiler would spuriously warn that X is uninitialized when it is referenced after the if_statement. Warnings are most useful if there are few false alarms. The compiler can avoid the false alarm if "Fatal_Error" were "raise ..."; pragma No_Return allows the same capability in the case where the programmer has chosen to encapsulate the raise statement.
3. Compilers can use this control-flow information for optimizations.
For example:
Y := F(...); if ... then Fatal_Error("..."); -- non-returning else Y := 3; end if; ... Y ... -- Y = 3.
A compiler can prove that Y = 3 above, and take advantage of that fact.
In order to gain the above advantages, we must ensure that the property asserted by the pragma is actually true; that is, calls to non-returning procedures must not return. In order to make this work for dispatching calls, we need to ensure that if a procedure is non-returning, then all overridings of it are also non-returning. We do this by requiring an explicit pragma on the overriding. An alternative would be to say that the non-returning property is inherited (implicitly) by the overriding procedure. We didn't choose that alternative, because it seems less safe. The programmer of the overriding might not notice the pragma No_Return on the parent procedure, and be surprised by a run-time failure; better to require the pragma to be repeated locally. Of course, a good compiler can usually warn about the potential run-time failure, but this is not required.
This issue is like any other part of the contract for procedure calls. For example, if you call a procedure with an 'in' parameter, you know that the actual will not be modified. To make this work for dispatching calls, we need to disallow overridings from changing 'in' to 'in out'.
If a non-returning procedure tries to return, we raise Program_Error. This is stated as happening at the call site, because we do not wish to allow the procedure to handle the exception (and then, perhaps, try to return again!). However, the expected run-time model is that the compiler will generate "raise Program_Error" at the end of the procedure body (but not handleable by the procedure itself), as opposed to doing it at the call site. (This is just like the typical run-time model for functions that fall off the end without returning a value). The reason is indirect calls: in "P.all(...);", the compiler cannot know whether P designates a non-returning procedure or a normal one. Putting the "raise Program_Error" in the procedure's generated code solves this problem neatly.
Similarly, if one passes a non-returning procedure to a generic formal parameter, the compiler cannot know this at call sites; the raise-in-body solution deals with this neatly.
There is one exception to the principle that "we must ensure that the property asserted by the pragma is actually true". For a pragma-Import procedure, it is the responsibility of the foreign-language code to obey the stated contract. This is the normal rule for interfacing pragmas, so we don't need to state this explicitly.
Note: procedure "exit", imported from C, is a reasonable example of an imported procedure that deserves a pragma No_Return.
The rule about renamings-as-body is also there to avoid an implementation burden, given the above intended run-time model. AARM-8.5.4(5.a/1) notes that implementations should be allowed to implement renaming-as-body using jumps; that implementation would not work if the renaming-as-body has to raise Program_Error. Given the above rule, the renaming-as-body can rely on the renamed procedure to raise Program_Error if appropriate. Anyway, a renaming-as-body that violates the rule is almost certainly a bug.
It would make sense to allow pragma No_Return on generic formal procedures, access-to-procedure types, entries, and protected procedures. We choose not to allow these cases, in order to avoid implementation burden and additional language rules for little benefit.
If access-to-procedure types allowed pragma No_Return, we would need a contract model to ensure that the designated procedure is always non-returning; we would forbid 'Access and type conversions that allow a non-returning access-to-procedure to designate a normal (returning) procedure. On the other hand, it would be OK for a normal access-to-procedure value to designate a non-returning procedure.
Similarly, generic formal procedures would need a contract: it should be illegal to pass a normal procedure to a non-returning formal, but the other way around is OK.
Pragma No_Return is like pragma Convention in some ways. It could actually affect the calling convention at the generated code level; for example, a call could use a JUMP instruction instead of a CALL instruction in some environments, although that's hardly an important optimization. However, pragma Convention is different in one way: it doesn't cause an automatic Program_Error. It has been suggested that No_Return be automatically inherited by overridings, just like Convention. But given that No_Return raises Program_Error, we choose to require an explicit No_Return on overridings.
[End AARM Discussion.]
!example
Example of a dispatching call to a non-returning procedure:
package Error_Handling is type Error_Log is abstract tagged null record;
procedure Fatal_Error(Log: Error_Log; Message: String) is abstract; pragma No_Return(Fatal_Error); -- Send a message to the log and raise an exception.
end Error_Handling;
-- A client of Error_Handling: Log: Error_Log'Class := Log_Factory.Create(...); if ... then Fatal_Error(Log, "The sky is falling!"); -- dispatching call -- Can't get here. else X := ...; -- initialize X end if; ... X ... -- no warning; if we get here, X is well-defined.
The idea is that there are different kinds of Error_Logs, which do what they like with the Message, and then raise an exception. It is natural to represent these log types using a hierarchy of tagged types, and to use dispatching. The above dispatching call to Fatal_Error is guaranteed not to return. The various extensions of Error_Log are required to override Fatal_Error with a non-returning procedure.
Clearly, if we are going to allow dispatching calls to non-returning procedures, then they need to work right -- the call must not return.
!discussion
The primary change to AI-00329 is to require dispatching calls to work properly. The other wording changes are just minor fixes to nitpicking problems:
Miscellaneous wording changes. The introductory paragraph is changed; I think the part bracketed in the AARM clarifies the two main purposes of the pragma. (A non-returning procedure could also presumably call a never-triggered entry, or delay until the year 2099; we don't mention these oddities). We can no longer use the "apply to" definition for program unit pragmas, since No_Return is no longer a program unit pragma; we define the term "non-returning procedure" instead.
The pragma is not a program unit pragma. It is now a representation pragma. This better matches the intended semantics.
The "procedure_local_name shall denote" wording better specifies which entities can have the pragma. AI-00329 forbade abstract procedures, but there's no reason to forbid them. AI-00329 apparently intended to allow renamings (in the usual "local_name" way), but it wasn't clear; now it's clear that they're allowed.
"The procedure_local_name shall not denote an instance of a generic unit." is added, because the legality rule "A return_statement shall not apply to a non-returning procedure or generic procedure." cannot be reasonably checked on instances.
AI-00329 did not consider renamings-as-body.
The rule "If a procedure declared within a generic unit is non-returning, then so are the corresponding copies of that procedure in instances." was apparently missing from AI-00329.
The rule, "A return_statement shall not apply to a non-returning procedure or generic procedure." does not strictly need the "or generic procedure" part, because inside the procedure body, it's a procedure (the current instance). Nonetheless, the rule seems clearer with the meaningless "or generic procedure" part.
!corrigendum 6.5.1(1)
Insert new clause:
A pragma No_Return indicates that a procedure cannot return normally; it may propagate an exception or loop forever.
Syntax
The form of a pragma No_Return, which is a representation pragma (see 13.1), is as follows:
pragma No_Return(procedure_local_name{, procedure_local_name});
Legality Rules
Each procedure_local_name shall denote one or more procedures or generic procedures; the denoted entities are non-returning. The procedure_local_name shall not denote a null procedure nor an instance of a generic unit.
A return_statement shall not apply to a non-returning procedure or generic procedure.
A procedure shall be non-returning if it overrides a dispatching non-returning procedure. In addition to the places where Legality Rules normally apply (see 12.3), this rule applies also in the private part of an instance of a generic unit.
If a renaming-as-body completes a non-returning procedure declaration, then the renamed procedure shall be non-returning.
Static Semantics
If a generic procedure is non-returning, then so are its instances. If a procedure declared within a generic unit is non-returning, then so are the corresponding copies of that procedure in instances.
Dynamic Semantics
If the body of a non-returning procedure completes normally, Program_Error is raised at the point of the call.
!ACATS test
In addition to the tests described in AI-329, create a B-Test to check that null procedures cannot have No_Return applied. Create a B-Test to check that No_Return is inherited. Create a B-Test to check that the rules of a representation pragma are properly checked for No_Return.
!appendix

From: Jean-Pierre Rosen
Sent: Tuesday, January 25, 2005  2:31 AM

When you give a pragma No_Return to a subprogram, does it apply to
subprograms derived from it?

If you think of No_Return as being some kind of contract, that would
certainly make sense, especially for dispatching calls.

Hoping not to open YACOW (Yet Another Can Of Worms)

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

From: Gary Dismukes
Sent: Tuesday, January 25, 2005 11:34 AM

Yes, No_Return should certainly apply to derived subprograms.
This should behave the same way as other program-unit pragmas
such as Inline (though I'm not sure where the rule is that
implies inheritance of pragmas like this).

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

From: Tucker Taft
Sent: Tuesday, January 25, 2005 12:26 PM

I'm not sure what you mean "derived subprograms."
Certainly the implicitly declared inherited subprogram
retains the No_Return, since it is just the same code.
But I don't see any rule, nor would I expect there to
be one, that says a subprogram that overrides such
an implicitly declared inherited subprogram automatically
inherits its program unit pragmas.  Inline being a good
example where the subprogram in the parent type might
be a good candidate for inlining, while the overriding
would not.

So I believe we need a special rule for No_Return, if
we want it.  It does make sense to me that if a primitive
procedure is declared No_Return, then so must be all
of its overridings.  But I am a bit reluctant for it
to be simply inherited.  I might rather require that the
No_Return be explicit on each overriding.  It has
a pretty dramatic effect, and I wouldn't want to have
someone add it during maintenance to the top of a hierarchy,
and suddenly discover that code deep down still compiled,
but started raising Program_Error all over the place.

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

From: Jean-Pierre Rosen
Sent: Tuesday, January 25, 2005 12:42 PM

Tucker Taft a ‚crit :
> I'm not sure what you mean "derived subprograms."
> Certainly the implicitly declared inherited subprogram
> retains the No_Return, since it is just the same code.
> But I don't see any rule, nor would I expect there to
> be one, that says a subprogram that overrides such
> an implicitly declared inherited subprogram automatically
> inherits its program unit pragmas.

That's the point.

> So I believe we need a special rule for No_Return, if
> we want it.  It does make sense to me that if a primitive
> procedure is declared No_Return, then so must be all
> of its overridings.  But I am a bit reluctant for it
> to be simply inherited.  I might rather require that the
> No_Return be explicit on each overriding.  It has
> a pretty dramatic effect, and I wouldn't want to have
> someone add it during maintenance to the top of a hierarchy,
> and suddenly discover that code deep down still compiled,
> but started raising Program_Error all over the place.

So the rule should be that the pragma is required for every overriding
of a "no_return" procedure, thus making a compilation error in the case
you mention. That's a good idea.

But now, what about the opposite way? Should we require that an
overriding subprogram specifies No_Return *only if* the overridden
subprogram has it? Actually, I can imagine that some primitive operation
is not applicable to some derived type, and that you override the
operation with one that always raises Program_Error...

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

From: Gary Dismukes
Sent: Tuesday, January 25, 2005 12:46 AM

> I'm not sure what you mean "derived subprograms."

I'm not sure who the "you" you're referring to is. :)

I interpreted that phrase as meaning inherited subprograms,
not overridings.  However I suppose that J-P was probably
referring to overridings since the answer seems obvious
for inherited ones (though I'm still not sure there's a
rule that actually implies that the pragma is inherited).

> ... Inline being a good
> example where the subprogram in the parent type might
> be a good candidate for inlining, while the overriding
> would not.

Sure, there's certainly no rule for carrying pragmas over
to overridings.

> So I believe we need a special rule for No_Return, if
> we want it.  It does make sense to me that if a primitive
> procedure is declared No_Return, then so must be all
> of its overridings.  But I am a bit reluctant for it
> to be simply inherited.  I might rather require that the
> No_Return be explicit on each overriding.  It has
> a pretty dramatic effect, and I wouldn't want to have
> someone add it during maintenance to the top of a hierarchy,
> and suddenly discover that code deep down still compiled,
> but started raising Program_Error all over the place.

I agree that it shouldn't be inherited.  But I'm not convinced
that it makes sense for it to be required to be given on overridings
(or am I misunderstanding you?).  It seems that it should be fine
for an overriding not to have No_Return semantics.  Why should
we impose that restriction on extensions?

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

From: Bob Duff
Sent: Tuesday, January 25, 2005 12:30 AM

I agree, although it might be nice to also have a way to say "this
procedure never returns, but overridings can be different".
This is the Eiffel problem that Tuck is fond of pointing out:
there's no way to make a contract that applies to a particular
procedure, as opposed to a whole tree of overridings.

One probably wants No_Return to apply to access-to-subprogram types as
well, but I suppose it's too late to bother with that for Ada 2005.

> This should behave the same way as other program-unit pragmas
> such as Inline (though I'm not sure where the rule is that
> implies inheritance of pragmas like this).

I don't remember any such general rule.

As to Inline, I don't see why you would want it inherited.
It's not a contract about the logical behavior of the thing
-- it's just a statement that this thing is small enough (or whatever)
to be inlined, which might be true or false independently for
overridings.  And for dispatching calls, I don't think you're normally
going to get inlining (although it's certainly possible in some cases).

There's no pragma Out_Of_Line, so it would be somewhat questionable to
have cases where inlining is requested implicitly (e.g. by
inheritance).

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

From: Bob Duff
Sent: Tuesday, January 25, 2005 12:32 AM

>   I might rather require that the
> No_Return be explicit on each overriding.

Yeah, that's an even better idea.

Either way, the point is that the compiler can know about it at call
sites -- including dispatching calls.

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

From: Tucker Taft
Sent: Tuesday, January 25, 2005  1:21 PM

> ...
> One probably wants No_Return to apply to access-to-subprogram types as
> well, but I suppose it's too late to bother with that for Ada 2005.
> ...

This seems certainly in the category of a desirable "tweak."  If we
are adding a new pragma, we should make sure it applies to
the appropriate kinds of entities.  No_Return is almost
like a new calling convention, and those apply to access-to-subp
as well (and are also required to be the same in overridings
of dispatching ops, by the way).  So I would say we should
have this apply to access-to-subp.  A No_Return acc-to-subp
may only designated No_Return subps.  On the other hand,
there is no problem for a "normal" (non-no-return) acc-to-subp
designating a No_Return subp.

Similarly, there should be no harm in overriding
a non-no-return subp with a no-return one,
but once you override with a no-return, then further
overridings should also be no-return, for a tagged primitive.

I suppose a formal subp should also allow a No_Return pragma,
with corresponding rules (i.e. actual must be No_Return).

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

From: Robert A. Duff
Sent: Tuesday, January 25, 2005  2:32 PM

> But now, what about the opposite way? Should we require that an
> overriding subprogram specifies No_Return *only if* the overridden
> subprogram has it?

No, because lack of No_Return does not promise that the thing *will*
return.  (And of course we can't very well say "raise P_E if so-and-so
loops forever"!)

>... Actually, I can imagine that some primitive operation
> is not applicable to some derived type, and that you override the
> operation with one that always raises Program_Error...

No_Return promises no *normal* return; a No_Return procedure can raise
whatever exceptions it likes (and, in fact, if it "tries" to return, it
*will* raise an exception).

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

From: Robert A. Duff
Sent: Tuesday, January 25, 2005  2:39 PM

> I agree that it shouldn't be inherited.  But I'm not convinced
> that it makes sense for it to be required to be given on overridings
> (or am I misunderstanding you?).  It seems that it should be fine
> for an overriding not to have No_Return semantics.  Why should
> we impose that restriction on extensions?

Because if you have a dispatching call to a No_Return procedure,
we would like the compiler to know for sure that it won't return,
so it can give appropriate warnings:

    X: Integer;
    if ... then
        Fatal_Error(...); -- dispatch on message stream type or whatever
        Put_Line("Hello, world!");
        ^ Warning: can't get here.
    else
        X := 1;
        ...
    end if;
    ... X ...
        ^ Do *not* warn here, about possibily-uninitialized X.

I believe your compiler is already that smart -- at least for
non-dispatching calls.

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

From: Tucker Taft
Sent: Tuesday, January 25, 2005  7:14 PM

> I agree that it shouldn't be inherited.  But I'm not convinced
> that it makes sense for it to be required to be given on overridings
> (or am I misunderstanding you?).  It seems that it should be fine
> for an overriding not to have No_Return semantics.  Why should
> we impose that restriction on extensions?

I think the issue is with class-wide calls.  My feeling
is that if a dispatching operation says it is
No_Return, then that should probably be true whether it is
called using statically or with run-time dispatch.
Hence, I think the overridings will need to honor
that pledge.  If you can think of a good example
where you have a routine that is something like
"Fatal_Error" and you would want overridings to
change the meaning enough so that it starts returning
rather than raising an exception, I might be
convinced.

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

From: Randy Brukardt
Sent: Tuesday, January 25, 2005  4:39 PM

This seems like overkill to me. It takes a relatively simple idea and
complicates it to the point where I would be against even having it in the
language. Moreover, this is a feature that is used rarely (maybe one out of
a thousand subprograms) - it simply doesn't pay to complicate it.

I would simply say that it applies to subprograms when given explicitly.
Implicitly inherited subprograms inherit it, of course, but that's it. You
wouldn't be able to give a warning on a dispatching call, but that's typical
anyway -- you generally can assume very little about class-wide types and
about dispatching calls. I think the likelyhood of a useful dispatching call
for No_Return is just about zero; probably it would only happen by accident
(that is, routines that were declared to be primitive but are never intended
to be overridden). I could imagine a pragma or keyword to declare *that*
property (it would be a lot more generally useful, especially as things need
to be primitive to make an object prefix call - since in the case of a
primitive routine that will never be overridden, there would be no need to
allocate a slot or do subprogram lookup in a tag for a dispatching call),
but not a lot of complication for No_Return.

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

From: Tucker Taft
Sent: Tuesday, January 25, 2005  8:55 PM

The four phases of an AI
  1) Ok, sounds simple, but you have to write it up
  2) Ok, we have a write-up, and still no major harm, so fine
  3) Oops, we forgot something in the write-up, so let's discuss
     it to death on the ARG list
  4) My god, with all this discussion, the feature must be
     incredibly complicated.  Forget the whole thing.

It often seems the amount of discussion about something is
inversely proportional to both how complicated it really is,
and to how important it really is.  ;-)

In this case, I think Jean-Pierre pointed out a legitimate
hole.  We have discussed it a while, and seem to have come
to an approximate consensus on how to properly deal with
the pragma w.r.t. inheritance, generics, and acc-to-subp.
If we don't discuss these things now, you can be sure they
will end up turning into 2005 AIs.  The rules seem fairly
straightforward, and are analogous to those for calling
conventions.

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

From: Pascal Leroy
Sent: Wednesday, January 26, 2005  5:17 AM

> This seems like overkill to me. It takes a relatively simple
> idea and complicates it to the point where I would be against
> even having it in the language. Moreover, this is a feature
> that is used rarely (maybe one out of a thousand subprograms)
> - it simply doesn't pay to complicate it.
>
> I would simply say that it applies to subprograms when given
> explicitly. Implicitly inherited subprograms inherit it, of
> course, but that's it.

I couldn't agree more.

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

From: Tucker Taft
Sent: Wednesday, January 26, 2005  9:23 AM

I don't want to complicate the feature, but it seems
pretty clear that if you declare a primitive of
a tagged type called something like "Fatal_Errror,"
and mark it as No_Return, then you would expect
all overridings to be the same.  Dispatching calls
are more important than non-dispatching calls for
many tagged types (certainly for Interfaces!),
and for these, No_Return should probably apply to dispatching
calls, and then the non-dispatching call requirements
are implied by the requirements of the dispatching call.

I agree these are not that common, but for something
like a window system, it is fairly typical to have
some way to pop up an "alert" box, including a "fatal alert"
(especially on Windows ;-).  I could imagine that something
like this might be something you would want to be able
to override, but if so, you wouldn't want to allow it
to become a "non-fatal" alert as part of overriding it.

In any case, I agree this isn't that critical, but it
does seem important whenever we define a new pragma, to
think carefully about how it interacts with inheritance,
generics, etc.  If we don't, we will just end up with
more AIs in the future.  In this case, it seems pretty
clear that you want all overridings to be No_Return,
if the original one is.

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

From: Pascal Leroy
Sent: Wednesday, January 26, 2005  10:46 AM

> I agree these are not that common, but for something
> like a window system, it is fairly typical to have
> some way to pop up an "alert" box, including a "fatal alert"
> (especially on Windows ;-).  I could imagine that something
> like this might be something you would want to be able to
> override, but if so, you wouldn't want to allow it to become
> a "non-fatal" alert as part of overriding it.

This is hardly a convincing example, because (other than the BSOD ;-) I
don't buy the notion that this would be a No_Return.  These things
typically have an OK button that returns you to the main event loop.

> In any case, I agree this isn't that critical, but it
> does seem important whenever we define a new pragma, to
> think carefully about how it interacts with inheritance,
> generics, etc.  If we don't, we will just end up with more
> AIs in the future.

I tend to agree with this, although I'd say that if it has this kind of
interaction with generics and inheritance, it violates the Rule of Good
Taste...

> In this case, it seems pretty clear that
> you want all overridings to be No_Return, if the original one is.

This is not at all clear to me.  I inherit from this base class and it
does all sorts of wonderful things for me, but it insists on calling the
No_Return procedure Fatal_Error when it detects an error.  Now in the
derived class there are situations where Fatal_Error is called, but which
are not really errors (this doesn't seem to violate the substitution
principle: I am extending the applicability of some operations).  I would
like to redefine Fatal_Error, maybe to look at the state of the object and
see if I really have a problem or not.

Ah but I see, if I returned normally from Fatal_Error, there might be code
in the base class that would be really surprised.  Yuck.  So No_Return is
really exposing a completely different control flow structure, and it
would seem that it is really part of the contract.

Of course, you would have to recheck that in the private part of
instantiations, too, just in case you have a subprogram there that
accidentally overrides a No_Return procedure inherited from the formal.

PS: I never liked this pragma.  I like it less and less.

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

From: Robert A. Duff
Sent: Wednesday, January 26, 2005  1:31 PM

It seems to me that if we're not going to go to the trouble of getting
the semantics right in the dispatching case, then we should forbid it.
(I.e. forbid this pragma on primitive ops of tagged types.)
At least that leaves the door open to future language revisions.
("Right" = what Tucker said.)

If we allow the pragma to be overridden, then we can't change our mind
due to compatibility.

The pragma is rarely useful.  So if it's disallowed in
generic/dispatching cases, well that's a wart, but not *so* bad.
Better than having it do the wrong thing!

> I tend to agree with this, although I'd say that if it has this kind of
> interaction with generics and inheritance, it violates the Rule of Good
> Taste...

You mean Good Taste in Pragmas?  It seems to me that a pragma that
allows a programmer to place restrictions on the code (to allow
optimizations, to allow better error detection, etc) are in Good Taste.
Bad taste are things like pragma Elaborate, which have a fundamental
effect on the semantics.

> Ah but I see, if I returned normally from Fatal_Error, there might be code
> in the base class that would be really surprised.

Exactly.

>...  Yuck.  So No_Return is
> really exposing a completely different control flow structure,...

Well, not really: infinite loops and always-raise are already legal!
The pragma merely documents this control flow structure.
Note that if you erase the pragma, the program behaves the
same (presuming it was correctly obeying the pragma).

>... and it
> would seem that it is really part of the contract.

Yes, it definitely should be part of the contract for dispatching calls;
otherwise, it's useless for dispatching calls.  Look at the examples in
the AI -- if you substitute dispatching calls, the benefits claimed by
the AI evaporate (without a contract model).

> Of course, you would have to recheck that in the private part of
> instantiations, too, just in case you have a subprogram there that
> accidentally overrides a No_Return procedure inherited from the formal.

Yes.

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

From: Randy Brukardt
Sent: Wednesday, January 26, 2005  3:16 PM

> You mean Good Taste in Pragmas?  It seems to me that a pragma that
> allows a programmer to place restrictions on the code (to allow
> optimizations, to allow better error detection, etc) are in Good Taste.
> Bad taste are things like pragma Elaborate, which have a fundamental
> effect on the semantics.

I disagree; pragmas that effect inheritance are in bad taste. You're going
to say something about convention, and I would be happy to say that those
are in bad taste. Convention should be part of the syntax, and so should
this pragma.

At this point, I would just forget it; it isn't worth these complications.
(It all about warnings, anyway, which Pascal is usually very opposed to.)

As a pragma that affects inheritance, it is very complicated to implement.
(I agree that is it similar to convention, but *that* is very complicated to
implement. I would be surprised if we have convention right in any
significant number of inheritance cases -- unless we simply don't allow it
on primitive operations of tagged types [I don't remember precisely what we
do with that]).

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

From: Tucker Taft
Sent: Wednesday, January 26, 2005  3:26 PM

> This is hardly a convincing example, because (other than the BSOD ;-) I
> don't buy the notion that this would be a No_Return.  These things
> typically have an OK button that returns you to the main event loop.

True, though frequently the way you get back to the main event loop is
by raising an exception.

> ...
>
>>In this case, it seems pretty clear that
>>you want all overridings to be No_Return, if the original one is.
>
>
> This is not at all clear to me.  I inherit from this base class and it
> does all sorts of wonderful things for me, but it insists on calling the
> No_Return procedure Fatal_Error when it detects an error.
> ...
> Ah but I see, if I returned normally from Fatal_Error, there might be code
> in the base class that would be really surprised.  Yuck.

Yes, and this might be code you inherit without overriding it.

 > ...  So No_Return is
> really exposing a completely different control flow structure, and it
> would seem that it is really part of the contract.

Calling a No_Return procedure is the moral equivalent of raising
an exception.  It is not "completely different" but it is
distinct from a procedure which is expected to not raise
an exception in the "normal" case.

> Of course, you would have to recheck that in the private part of
> instantiations, too, just in case you have a subprogram there that
> accidentally overrides a No_Return procedure inherited from the formal.

Yes.

> PS: I never liked this pragma.  I like it less and less.

Give it a chance.  It will grow on you.  Honestly, it really
is a fundamental property of a procedure (perhaps *the*
fundamental property of a procedure), and it makes a pretty
big difference when you see code like:

    if not blah then
         Never_Return(xxyyzz);
    end if;
    -- assuming "blah" at this point

It is fundamental to understanding what is going on in code like
the above.  We would understand it clearly if there
were a "return", "goto", "exit", or "raise" there, but
without some clear specification that Never_Return is
a No_Return procedure, the above is a mystery, to both
the human reader and to any sort of tool.  By making
it a standard pragma, portable code can be written
where the compiler will ensure that such a routine
definitely does *not* return.  A commenting convention
can't accomplish that.

Note that this pragma was not invented by some pointy-headed
language lawyer.  This arose in two implementations in
response to needs involving real user code. I have seen
a number of coding conventions that pretty much require
that all fatal errors be reported via calling a particular
procedure, rather than just raising an exception in-line.

The idea of such an annotation goes at least as far back
as the original "lint" program -- it's not very radical.
Why is it important now?  Because more and more effort is
being put into finding bugs at compile-time, or at least
before run-time.  Ada should be a leader here, but without
a standard annotation like this, there is a huge hole in
doing any sort of modular analysis of the code.

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

From: Randy Brukardt
Sent: Wednesday, January 26, 2005  3:50 PM

> It is fundamental to understanding what is going on in code like
> the above. We would understand it clearly if there
> were a "return", "goto", "exit", or "raise" there, but
> without some clear specification that Never_Return is
> a No_Return procedure, the above is a mystery, to both
> the human reader and to any sort of tool. By making
> it a standard pragma, portable code can be written
> where the compiler will ensure that such a routine
> definitely does *not* return.  A commenting convention
> can't accomplish that.

Absolutely. But if it is that fundamental, then it *must not* be a pragma;
pragmas are meant to be ignored when reading code. This is something that
should be clearly stated in the specification of the procedure.

It's very much like the overriding indicators. We tried them as pragmas, but
they are too fundamental to be such.

It is inappropriate for this to be a pragma if it starts applying all over
the place.

> Note that this pragma was not invented by some pointy-headed
> language lawyer.  This arose in two implementations in
> response to needs involving real user code.

Because those implementations couldn't invent syntax. And so far as I know,
neither of those implementations make the requirement that this pragma is
inherited.

> Ada should be a leader here, but without
> a standard annotation like this, there is a huge hole in
> doing any sort of modular analysis of the code.

I'm happy with the pragma as currently specified (no magic, no muss). But if
you want to go further, it has to be a syntactic annotation. It has to
matter when matching for formal subprograms (shouldn't it be able to apply
to them too?) It has to be checked on 'Access. This is a substantial job
(not like the current pragma, which only changes the drop-out return to
raise Program_Error, and has no other effect).

I'm willing to consider the whole boat of syntax for this (although it is
awfully late), but extending the simple pragma into this complex beast is a
non-starter for me. I'd rather forget the whole thing and let the
implementers do what makes sense for their implementations.

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

From: Robert I. Eachus
Sent: Wednesday, January 26, 2005  11:53 PM

Tucker Taft wrote:

> Note that this pragma was not invented by some pointy-headed
> language lawyer.  This arose in two implementations in
> response to needs involving real user code. I have seen
> a number of coding conventions that pretty much require
> that all fatal errors be reported via calling a particular
> procedure, rather than just raising an exception in-line.

I agree with Tucker here and in the rest of his message.  I think the
point that is getting lost is that there are many, many real-time
programs where it is a fundamental property of the main processing
procedure that it never returns.

There are many optimizations that can be made if the compiler knows that
a procedure does not return which are important not because they
significantly speed up the code--which they often do--but because they
prevent accidental Hayflick limits from being created.  The Hayflick
limit is the built-in feature of most cell reproduction that limits the
number of times a cell can divide.  In cells, Hayflick limits help
prevent cancer. In code they are among the worst kinds of bugs to trace
down.   If a radar has an accidental limit of this kind, the testers may
never discover it, and the angst that will be produced once the error
does cause a service failure is very real.

I have been involved in the heroic efforts to find this type of bug on
occasion and it is not pretty.  In most cases they are unusual code
paths that result in something getting pushed on the stack and left
there.  If a normal return occurs, the current stack frame and any
extensions are popped off, and subtle memory losses get fixed.
Procedures that will never return, will never clean the stack this way,
so they can't afford to call subroutines which are poorly behaved.  In
the OS realm, this usually means calling the user visible entry point,
rather than the (faster) alternative that does not do error checking,
and often does not create a stack frame of its own.

This is what I think of when considering pragma No_Return.  Yes, it can
make some compiler diagnostics better and so on in the case where the
subroutine always raises an exception.  But the diagnostics I care about
are program verifier related.  I want the verifier to check both the
property that the code cannot raise an exception (or sometimes only
cannot raise a predefined exception) and subprograms marked as never
exiting never exit.

How does this apply to the discussion so far?  I think Tuck's proposal
that subprograms that inherit an interface declared as No_Return must
also be declared to be No_Return is fine.  Even if the attribute was
inherited, I'd probably put such a requirement in the SDP.  Why?  Well
you want the property to compose correctly:

    procedure Main;
    pragma No_Return(Main);
    ....
    procedure Main_Execution_Loop;
    procedure Test_Execution_Loop;
    pragma No_Return(Main_Execution_Loop, Test_Execution_Loop);
    ...
    procedure Main_Execution_Loop is
    begin
        loop
           ... -- no returns or loop exits allowed here.
       end loop;
    end Main_Execution_Loop;
    ...
    procedure Main is
    begin
        if  Test_Mode
        then Test_Execution_Loop;
        else  Main_Execution_Loop;
        end if;
     end Main;

Obviously I want tools, one of which is the compiler, to be able to
reason that if No_Return is correct for Main_Execution_Loop and
Test_Execution_Loop, then it is correct for Main.  But more important to
me is that the compiler should realize that the evaluation of Test_Mode
should not leave cruft on the stack until the end of the if, and
definitely any resources acquired or locked during the evaluation must
be returned before the then or else parts.

Anyone who used Multics prior to 8.0? will recognize the issue.  The
Multics PL/I compiler did have cases where complex expressions in the if
clause could cause memory to be used, and it wouldn't be released until
the end of the if statement.  Actually early on, it only released the
memory at the end of the else part, but that got fixed quickly.  However
if you did a goto out of the if statement, it still could result in a
memory leak.  Obviously it was fixed, but the full fix required two
compiler releases and a flag day.
(http://jargon.watson-net.com/jargon.asp?w=flag+day)

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

From: Pascal Leroy
Sent: Thursday, January 27, 2005  1:36 AM

> But the diagnostics I care about
> are program verifier related.  I want the verifier to check both the
> property that the code cannot raise an exception (or sometimes only
> cannot raise a predefined exception) and subprograms marked as never
> exiting never exit.

Two comments here.  One is that the pragma doesn't ensure that the
subprogram in question "never exits".  It ensures that it doesn't return
normally.  So it can very well exit by raising an exception.  You seem to
assume that the main usage of this pragma is for infinite loops, but it is
really the case of procedures that raise an exception that was mostly
discussed.

Moreover, I am skeptical about adding in the language pragmas that are
intended for program verifiers.  It seems quite hard to know in general
which pragmas are going to be useful for a particular verifier: I suspect
that it depends heavily on what kind of analysis the verifier is capable
of doing.  Of course the compiler is one particular kind of program
verifier, but then we are mostly talking warnings (yawn) and optimization
(re-yawn).

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

From: Jean-Pierre Rosen
Sent: Thursday, January 27, 2005  3:15 AM

> At this point, I would just forget it; it isn't worth these complications.
> (It all about warnings, anyway, which Pascal is usually very opposed to.)

I think this the crux of the argument: You (and Pascal I think) view
this pragma as simply a mean of removing useless warning messages, while
others view it as a contract model element, that is useful for the human
reader (as well as tools).

I have some sympathy with your idea that the second option requires true
syntax, not a pragma, and the comparison with [not] overriding is quite
convincing. Are we ready to go all the way to:
    [not return] [[not] overriding] procedure Blah is....

or (not really serious):
    all return with exception procedure Blah is...

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

From: Tucker Taft
Sent: Thursday, January 27, 2005  8:27 AM

Note that No_Return is an existing pragma in several
implementations, and it has all the right
characteristics of a pragma, namely that adding it has
no effect on correct programs that continue
to compile.

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

From: Jean-Pierre Rosen
Sent: Thursday, January 27, 2005  9:34 AM

Of course, and nothing would prevent existing implementations to
continue supporting the pragma, with the current (absence of) semantics
for derived subprograms.

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

From: Pascal Leroy
Sent: Thursday, January 27, 2005  9:43 AM

Bob wrote:

> >...  Yuck.  So No_Return is
> > really exposing a completely different control flow structure,...
>
> Well, not really: infinite loops and always-raise are already
> legal! The pragma merely documents this control flow
> structure. Note that if you erase the pragma, the program
> behaves the same (presuming it was correctly obeying the pragma).

So far so good, but then we don't require an always-raise procedure to
only be overridden by always-raise procedures.  So the pragma is not
merely documenting the control flow.  It is promising a contract that is
enforced across type derivation, and presumably generic instantiations.

I am not saying that this is necessarily a bad idea -- I would need to
give it more thought.  But I surely never realized that this pragma had
such a far-reaching semantic effect.  And surely a pragma that
dramatically affects the legality of a program falls into the Bad Taste
category.  So I would be enclined to agree with Randy, syntax would be
better here (and it's awfully late).

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

From: Robert Dewar
Sent: Friday, January 28, 2005  6:10 AM

>>I would simply say that it applies to subprograms when given
>>explicitly. Implicitly inherited subprograms inherit it, of
>>course, but that's it.
>
>
> I couldn't agree more.

I also agree with this, why do we have to complexify everything?
One of the hardest things for us to implement was the absurdly
over-decorated version of Unchecked_Union, including all kinds
of bells and whistles that none of our users have even suggested
in the many years we have implemented this. Let's not kill
No_Return by similar overzealous attention :-)

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

From: Robert Dewar
Sent: Friday, January 28, 2005  6:12 AM

> The pragma is rarely useful.

The main use in practice is to suppress spurious warnings about
missing return paths in functions. It really has no semantics to
speak of :-)

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

From: Robert Dewar
Sent: Friday, January 28, 2005  6:11 AM

Tucker Taft wrote:
> I don't want to complicate the feature, but it seems
> pretty clear that if you declare a primitive of
> a tagged type called something like "Fatal_Errror,"
> and mark it as No_Return, then you would expect
> all overridings to be the same.  Dispatching calls
> are more important than non-dispatching calls for
> many tagged types (certainly for Interfaces!),
> and for these, No_Return should probably apply to dispatching
> calls, and then the non-dispatching call requirements
> are implied by the requirements of the dispatching call.

It does not seem clear to me!

> I agree these are not that common, but for something
> like a window system, it is fairly typical to have
> some way to pop up an "alert" box, including a "fatal alert"
> (especially on Windows ;-).  I could imagine that something
> like this might be something you would want to be able
> to override, but if so, you wouldn't want to allow it
> to become a "non-fatal" alert as part of overriding it.

I discourage imagination, and suggest relying on actual
user experience instead.

> In any case, I agree this isn't that critical, but it
> does seem important whenever we define a new pragma, to
> think carefully about how it interacts with inheritance,
> generics, etc.  If we don't, we will just end up with
> more AIs in the future.  In this case, it seems pretty
> clear that you want all overridings to be No_Return,
> if the original one is.

I don't think this is critical

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

From: Robert Dewar
Sent: Friday, January 28, 2005  6:16 AM

Randy Brukardt wrote:

> Because those implementations couldn't invent syntax. And so far as I know,
> neither of those implementations make the requirement that this pragma is
> inherited.

As I said earlier, the main motivation for introducing this in GNAT
was to suppress junk warnings. Yes, it is used a bit for optimization
purposes, but that may have been a mistake, since the gain is minimal
and it has caused over time some (now fixed) problems. A pragma was
definitely more appropriate, since it has no detectable semantics (i.e.
you cannot write a test program to make sure it has been properly
implemented).

> I'm happy with the pragma as currently specified (no magic, no muss). But if
> you want to go further, it has to be a syntactic annotation. It has to
> matter when matching for formal subprograms (shouldn't it be able to apply
> to them too?) It has to be checked on 'Access. This is a substantial job
> (not like the current pragma, which only changes the drop-out return to
> raise Program_Error, and has no other effect).

Ada is not in the business of these kind of annotations, leave that to
SPARK :-)

> I'm willing to consider the whole boat of syntax for this (although it is
> awfully late), but extending the simple pragma into this complex beast is a
> non-starter for me. I'd rather forget the whole thing and let the
> implementers do what makes sense for their implementations.

I am not (willing to consider syntax boats).

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

From: Robert A. Duff
Sent: Friday, January 28, 2005  9:13 AM

> > If we allow the pragma to be overridden, then we can't change our mind
> > due to compatibility.
> >
> > The pragma is rarely useful.

...in the sense that very few procedures will be no-return procedures.
But such procedures are typically called all over the place
(and the corresponding benefit in warning generation/suppression
and optimization occurs all over).

> The main use in practice is to suppress spurious warnings about
> missing return paths in functions.

Well, I don't know what particular compilers do with it, but it is
potentially much more general that just that particular warning.
Lots of warnings could be suppressed by knowing that a particular
control-flow path can't happen.  (Tucker gave an example of an uninit
variable warning.)  And misc optimizations can benefit from
the same knowledge.

Warnings are useless if there are too many spurious ones, so it's a Good
Thing to give the compiler knowledge that can suppress the spurious
ones.

>... It really has no semantics to
> speak of :-)

Heh?  According to the AI, the semantics (for nondispatching calls only)
is that the call will not return normally.  This is enforced, and the
compiler can therefore believe it.

The fact that this property is broken for dispatching calls seems
obviously wrong to me.  I feel quite strongly that if we're not going to
do dispatching calls right, we should forbid the pragma on dispatching
procedures!  Otherwise, the pragma has negative benefit (it's an
outright lie).

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

From: Robert A. Duff
Sent: Friday, January 28, 2005  9:55 AM

I wrote:

> This is enforced, and the
> compiler can therefore believe it.

Just to clarify:  I mean that the no-returning property is enforced ON
THE BODY, and the compiler (and programmer) can therefore believe it (AT
THE CALL SITE).

It's like any other part of the contract.  For example, if you call a
procedure with an 'in' parameter, you know that it won't modify the
actual.  To make this work for dispatching calls, we obviously have to
disallow overriding that 'in' parameter with an 'in out' parameter.

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

From: Robert Dewar
Sent: Saturday, January 29, 2005  5:12 PM

That sounds like a convincing argument to me.

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

From: Erhard Ploedereder
Sent: Friday, January 28, 2005  8:07 AM

Let's do a bit of code review....

type T is tagged ....
    procedure P(X: T);
    pragma No_Return(P);

-----
if somepred then
      P(O);
      notify_the_police("help, we're dying");       -- (1)
else ....


As I code reviewer, I would find the statement at --(1) extremely
suspicious, since it has the strong smell of dead code.
Absent the pragma, I would not (easily) find out that the statement is dead
code, if P is indeed a non-returning procedure.

In that sense, the pragma makes a contribution to code safety, not just
to suppress annoying warnings by compilers.
In that sense, too, the pragma must be "inherited", i.e., observed by
redefinitions. (Whether one insists on an explicit confirmation as part
of the redefinition is a secondary question. I am mildly opposed to
require this.)

It just isn't correct, if a call on a routine amended by a comment, a
pragma, syntax, or whatever that says that the routine will not return, does
return after all.

If you really insist that the pragma be merely a warning suppressing
pragma, it belongs in the body of the respective routine, and only
there.

Actually, the pragma smells a lot more like a calling convention pragma
(with all the right rules already in place) than a pragma akin to Inline.

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

From: Robert Dewar
Sent: Saturday, January 29, 2005  5:11 AM

> If you really insist that the pragma be merely a warning suppressing
> pragma, it belongs in the body of the respective routine, and only
> there.

No, that won't do, it is the client that must suppress the warning
and hence needs to know that this is going on.

> Actually, the pragma smells a lot more like a calling convention pragma
> (with all the right rules already in place) than a pragma akin to Inline.

I absolutely agree that this is anaologous to a calling convention. In
fact it really is part of the calling convention (which covers call
and return).

For example, in some environments, you could imagine that pragma No_Return
causes the compiler to generate a jump instead of a call instruction.

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

From: Bob Duff
Sent: Wednesday, February 2, 2005 11:35 AM

Pascal has asked me to write an AI that corrects AI-329 -- pragma
No_Return.  But I've gotten myself confused.

Pragma No_Return is a program unit pragma.  It is modeled after pragma
Inline, which is also a program unit pragma.  10.1.5 says:

                            Name Resolution Rules

2     {program unit pragma [distributed]} {pragma, program unit
 [distributed]} Certain pragmas are defined to be program unit pragmas.
{apply (to a program unit by a program unit pragma) [partial]} A name given as
the argument of a program unit pragma shall resolve to denote the declarations
or renamings of one or more program units that occur immediately within the
declarative region or compilation in which the pragma immediately occurs, or
it shall resolve to denote the declaration of the immediately enclosing
program unit (if any); the pragma applies to the denoted program unit(s). If
there are no names given as arguments, the pragma applies to the immediately
enclosing program unit.

                               Legality Rules

3     A program unit pragma shall appear in one of these places:

4     At the place of a compilation_unit, in which case the pragma shall
      immediately follow in the same compilation (except for other pragmas) a
      library_unit_declaration that is a subprogram_declaration, generic_-
      subprogram_declaration, or generic_instantiation, and the pragma shall
      have an argument that is a name denoting that declaration.

5/1   {8652/0033} Immediately within the declaration of a program unit and
      before any nested declaration{ (but not within a generic formal part)},
      in which case the argument, if any, shall be a direct_name that denotes
      the immediately enclosing program unit declaration.

6     At the place of a declaration other than the first, of a
      declarative_part or program unit declaration, in which case the pragma
      shall have an argument, which shall be a direct_name that denotes one or
      more of the following (and nothing else): a subprogram_declaration, a
      generic_subprogram_declaration, or a generic_instantiation, of the same
      declarative_part or program unit declaration.

Para 2 seems to contemplate program unit pragmas that refer to
renaming_declarations.  But paras 4 and 6 seem to forbid renamings.
A subprogram_renaming_declaration is not a subprogram_declaration.

6.3.2 says:

    5.a   Ramification: Note that inline expansion is desired no matter what
          name is used in the call. This allows one to request inlining for
          only one of several overloaded subprograms as follows:

    5.b   package IO is
             procedure Put(X : in Integer);
             procedure Put(X : in String);
             procedure Put(X : in Character);
          private
             procedure Character_Put(X : in Character) renames Put;
             pragma Inline(Character_Put);
          end IO;

But the above pragma Inline seems illegal by 10.1.5(6).

Is this a bug in the RM, or am I missing something?

Regardless of the pragma Inline issue, I'm thinking pragma No_Return
should *not* be a program unit pragma.  It should be a representation
pragma, modeled after pragma Convention.  Does that make sense?

An implementation could use a JUMP instruction instead of a CALL
instruction to call a No_Return procedure.  This isn't the primary
purpose of the pragma, but it seems reasonable to allow this
optimization.  Making No_Return a representation pragma makes sense
here, because that implies some freezing rules -- the compiler needs to
know it's a No_Return procedure before any calls.

Should No_Return be allowed on a renaming_decl?  If so, should it have
the same weird semantics as for pragma Inline?

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

From: Gary Dismukes
Sent: Wednesday, February 2, 2005 12:55 PM

> But the above pragma Inline seems illegal by 10.1.5(6).
>
> Is this a bug in the RM, or am I missing something?

Hmm, this does seem like a bug, given that the name in the pragma is
required to denote one of those specific forms of declaration, rather
than, say, denoting the entity declared by one of those (which would
capture the renaming case I think).

> Regardless of the pragma Inline issue, I'm thinking pragma No_Return
> should *not* be a program unit pragma.  It should be a representation
> pragma, modeled after pragma Convention.  Does that make sense?

Yes, that seems reasonable.  In any case, it probably doesn't that much
sense to allow this pragma to be nested within the body of the subprogram
that it applies to, as program unit pragmas allow.

> An implementation could use a JUMP instruction instead of a CALL
> instruction to call a No_Return procedure.  This isn't the primary
> purpose of the pragma, but it seems reasonable to allow this
> optimization.  Making No_Return a representation pragma makes sense
> here, because that implies some freezing rules -- the compiler needs to
> know it's a No_Return procedure before any calls.
>
> Should No_Return be allowed on a renaming_decl?  If so, should it have
> the same weird semantics as for pragma Inline?

If we make it a representation pragma then it would seem to be allowed
for renamings (that occur immediately within the same set of declarations),
since the wording for such pragmas talks about denoting an entity.
I don't see any particular problem with allowing those, and it would
allow disambiguation in the same manner as Inline.

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

From: Tucker Taft
Sent: Wednesday, February 2, 2005 12:27 PM

> Para 2 seems to contemplate program unit pragmas that refer to
> renaming_declarations.  But paras 4 and 6 seem to forbid renamings.
> A subprogram_renaming_declaration is not a subprogram_declaration.

This sounds like a bug.  Para 6 should allow
subprogram_renaming_declaration as well.  No need
for that in para 4, because library units can't
be overloaded.  Note that in Ada 83, the wording
talks about denoting a subprogram, as opposed to
a subprogram_declaration.  As suggested below, para 6
wording should probably be similar to 13.1(6) which
allows denoting a local subprogram via a local
renaming.

>
> ...
>
> Is this a bug in the RM, or am I missing something?

I think it is a bug.

>
> Regardless of the pragma Inline issue, I'm thinking pragma No_Return
> should *not* be a program unit pragma.  It should be a representation
> pragma, modeled after pragma Convention.  Does that make sense?

Not quite.  Pragma Convention, when applied to a program unit,
*is* a program unit pragma.  It is also a representation pragma.
It's both (I can almost hear the TV advertisement for this ;-).
See B.1(29).

> Should No_Return be allowed on a renaming_decl?  If so, should it have
> the same weird semantics as for pragma Inline?

If it is a representation pragma, then it should use the "local_name"
semantics, which allows denoting an overloadable entity via
a rename, to resolve ambiguity (see 13.1(6)).  Pragma Convention
allows this, for example.

It might be nice if para 10.1.5(6) and 13.1(6) shared more wording.
Right now I think they are trying to say about the same thing,
but 13.1(6) got it right, and 10.1.5(6) seems to have muffed it.

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

From: Randy Brukardt
Sent: Wednesday, February 2, 2005  2:30 PM

> But the above pragma Inline seems illegal by 10.1.5(6).
>
> Is this a bug in the RM, or am I missing something?

I was sure that we'd already discussed this in the past, but I can't find
anything in the AIs. Must be a deja vu experience.

(Yes, if you want inheritance and the like of No_Return, then it should be
treated like a Convention pragma. Indeed, it *is* a convention; perhaps we
should just define this as a convention name?)

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

From: Gary Dismukes
Sent: Wednesday, February 2, 2005  2:38 PM

> I was sure that we'd already discussed this in the past, but I can't find
> anything in the AIs. Must be a deja vu experience.

Interesting, I had a similar deja vu feeling.

> (Yes, if you want inheritance and the like of No_Return, then it should be
> treated like a Convention pragma. Indeed, it *is* a convention; perhaps we
> should just define this as a convention name?)

This property seems orthogonal to convention.  It seems that making it a
convention would prevent exporting such a procedure to foreign code.

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

From: Randy Brukardt
Sent: Wednesday, February 2, 2005  3:02 PM

> This property seems orthogonal to convention.  It seems that making it a
> convention would prevent exporting such a procedure to foreign code.

Which seems like a good thing if it actually *does* change the convention,
as Bob suggested. Moreover, I can't imagine what use it would have in
foreign code, which isn't going to be able to do anything with an Ada
exception.

In any case, pragmas are inappropriate for this. (That includes Convention;
it would be much better if we had done that syntactically:

    procedure Something (A : Integer) as Fortran is ...

But it's too late for that.) We're stuck with Convention (and Pack), but I'm
strongly opposed to adding more. At least reusuing Convention would be
something that I couldn't really object to...

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

From: Gary Dismukes
Sent: Wednesday, February 2, 2005  3:22 PM

Some implementations support importing and exporting of exceptions.
For example, JGNAT allows importing Java exceptions, which can be
raised and propogated to Java code.

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

From: Robert Dewar
Sent: Wednesday, February 2, 2005  3:54 PM

Perhaps I miss something, but a standard use of pragma No_Return is
for the imported exit function.

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

From: Erhard Ploedereder
Sent: Thursday, February 3, 2005  6:45 AM

I agree with Gary. It is an orthogonal convention aspect and, if tied to
convention semantics, should be an aspect that can be additional to the
calling cenvention and one that is immutable by overriding. (In fact, it
is not at all unlikely that calling convention C and the No-Return
convention should both apply to a subprogram.)

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

From: Robert Dewar
Sent: Wednesday, February 2, 2005  4:38 PM

> > Is this a bug in the RM, or am I missing something?
>
> I was sure that we'd already discussed this in the past, but I can't find
> anything in the AIs. Must be a deja vu experience.

Strange.  ;-)

> (Yes, if you want inheritance and the like of No_Return, then it should be
> treated like a Convention pragma. Indeed, it *is* a convention; perhaps we
> should just define this as a convention name?)

I just sent out my AI on the topic of No_Return.  I think I answered
this in the AI -- No_Return is somewhat like Convention, but not
entirely.  I agree with Gary that it doesn't work to simply make it
another Convention name.

I have some sympathy for Randy's idea that No_Return should be syntax
rather than a pragma.  That's probably how I'd design a from-scratch
language.  But it *is* a pragma, approved by WG9, and I'm just trying to
get the details right.  At this late date (for Ada 2005), we don't need
"It should be syntax.  So propose some syntax.  So nobody likes the
syntax.  So squelch the whole idea."  Let's focus on getting the details
right, and ignore the fact that we might like a totally different
approach.

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

From: Robert Dewar
Sent: Wednesday, February 2, 2005  3:51 PM

> In any case, pragmas are inappropriate for this. (That includes Convention;
> it would be much better if we had done that syntactically:
>
>     procedure Something (A : Integer) as Fortran is ...

BIG UGH! Uninterpreted identifiers outside pragmas, please no. I think
pragma Convention is just fine.

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

From: Randy Brukardt
Sent: Wednesday, February 2, 2005  4:44 PM

I don't see the issue; it's no different than First and Last, which are also
magic identifiers.

But it's academic in any case.

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

From: Robert Dewar
Sent: Wednesday, February 2, 2005  5:17 PM

Pragma names and attribute names are indeed handled specially. Please don't
add more special cases, they would be a real pain to implement!

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

From: Randy Brukardt
Sent: Wednesday, February 9, 2005  9:57 PM

> Uninterpreted identifiers outside pragmas, please no. I think
> pragma Convention is just fine.

Why would they be uninterpreted? The AARM suggests that the convention names
could have been an enumeration declared in package Interfaces (with
implementation-defined contents); that would prevent problems. Obviously, the
expression used would have to be static; but it would allow giving alternative
names to these things simply -- it certainly would have helped us when we
decided to follow others lead and rename our "Windows" convention to "StdCall".

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

From: Robert A. Duff
Sent: Wednesday, February 2, 2005  4:28 PM

OK, here's a new AI to replace AI-00329, as requested by Pascal. [This is
version /01 - ED.] The only major change is to make dispatching calls work
right (they don't return if so-promised by the pragma).  I noticed a few other
minor problems with AI-00329, which I patched up in the wording.  None of this
is a big deal, and none of it causes any big implementation burdens.

I think the dispatching calls issue needs to be fixed *now*, because fixing it
in AI2005-00001 would raise compatibility problems.  Various extensions have
been suggested (e.g. access-to-procedure types); these need not be fixed now.
They can be easily fixed compatibly in 2010 or 2015, or never.  Therefore, this
AI does not propose to add those capabilities.  For simplicity's sake, I
have only fixed bugs, and not added gratuitous features.

There is, apparently, a bug in the rules about "program unit pragmas".
I did not fix that.  If somebody wants an AI on that, I'm willing to write it,
but it's irrelevant to *this* AI.

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

From: Robert I. Eachus
Sent: Wednesday, February 2, 2005  9:06 PM

I will state this as a bit of missing justification from the AI:  There
is no mention of why No_Return is limited to procedures and cannot be
applied to functions.  At first thought, No_Return for functions may
seem completely silly, but one of the examples renames the C function
exit.  (It is not a procedure, C doesn't have such things.)

The only reason for allowing No_Return to apply to functions I can see
is completeness.  Certainly if a function calls a procedure marked
No_Return, you would like to apply the pragma to a function as well.

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

From: Robert Dewar
Sent: Wednesday, February 2, 2005  9:45 PM

> At first thought, No_Return for functions may
> seem completely silly, but one of the examples renames the C function
> exit.  (It is not a procedure, C doesn't have such things.)

C has void functions like exit, which properly map into Ada procedures,
so this concern is pedantic and irrelevant in my view.

> The only reason for allowing No_Return to apply to functions I can see
> is completeness.  Certainly if a function calls a procedure marked
> No_Return, you would like to apply the pragma to a function as well.

This seems to be orthogonality gone berserk.

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

From: Bob Duff
Sent: Thursday, February 3, 2005  7:07 AM

AI-329 has some rationale for that.  I didn't repeat the content of
AI-329 in the new AI.  The new AI is about fixing a fairly important
bug, and fixing a few minor nits.  The only rationale in the new AI is
rationale for these bug fixes, and I think that's as it should be.

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

From: Robert I. Eachus
Sent: Sunday, February 6, 2005  12:43 PM

My only intention was to suggest that *if* this AI is a replacement for AI-329,
it should keep the rationale from AI-329...

Robert Dewar wrote:

> C has void functions like exit, which properly map into Ada procedures,
> so this concern is pedantic and irrelevant in my view.

Which concern?  I thought I was saying that the AI should provide a
justification for, in effect, requiring that C functions which don't
return should be declared as Ada procedures.

I said:

>> The only reason for allowing No_Return to apply to functions I can
>> see is completeness.  Certainly if a function calls a procedure
>> marked No_Return, you would like to apply the pragma to a function as
>> well.

Robert Dewar responded...

> This seems to be orthogonality gone berserk.

Or a vivid imagination.  My intent was not to argue in favor of pragma
No_Return applying to functions.  I was just saying that the only
possible argument I could see in favor of it was orthogonality.  Maybe
someone could imagine some other strawman?

In any case, the current version of AI-329 (1.8) says:

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.

I also won't complain if more of the discussion section of AI-329 is
carried over into the new AI.  Since AI-329 is already WG-9 approved,
and this AI references it, that may be sufficient.  If the intent is for
the new AI to supplement AI-329 instead of replacing it, that is fine.

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

From: Bob Duff
Sent: Sunday, February 6, 2005  2:28 PM

OK, now I see what you mean.

I should not have said "replace" -- sorry.  The wording of the new AI
replaces *most* of the wording of AI-329, but it explicitly mentions
that a couple of paragraphs are carried over from AI-329.

Also, I didn't want to Rationalize the existence of the feature --
AI-329 already does that, and I think referring to it is enough.  The
new AI should Rationalize the changes, I think.

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


Questions? Ask the ACAA Technical Agent