Version 1.4 of ais/ai-00278.txt

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

!standard 09.05.02 (27)          01-10-17 AI95-00278/01
!class amendment 01-10-17
!status work item 01-10-17
!status received 01-10-10
!priority Low
!difficulty Medium
!subject Task Entry without Accept Statement
!summary
Require that all entry declaration have at least one matching accept statement.
!problem
Ada 95 allows the declaration of an entry with no corresponding accept. A deadlock may occur for a call to such an entry. Ada's safety requirements suggest that this case be an error.
!proposal
(Specific wording changes TBD.)
!discussion
This sort of check is similar to the existing requirement that a function have at least one return statement. That requirement also pushes run-time errors to compile-time.
This change is incompatible with Ada 95, but the fix (assuming that the entry is actually needed in the program) is easy -- simply surround an accept with an if statement:
if False then accept Foo; end if;
Moreover, tasks which have no accept statement for one of their entries are likely to be very rare.
!example
!ACATS test
!appendix

!topic Task Entry Without Accept Statement
!reference RM95-9.5.3(17 on page 168)
!from Anh Vo 01-10-10
!keywords entry accept task
!discussion
NOTES
(22) A task entry has corresponding accept_statements (zero or more), whereas a
protected entry has a corresponding entry_body (exactly one).

I would like to suggest to rephrase notes 22 as shown below

(22) A task entry has corresponding accept_statements (one or more), whereas a
protected entry has a corresponding entry_body (exactly one).

The consequences of the current requirements are that a dead lock surely occurs
for an entry without at least one corresponding accept statement. Has any body
faced this situation before? I sure have. If you are troubleshooting a task dead
lock in this situation, I am sure you will be happy to see this change. This
suggestion is totally compatible with the current version. It only affects the
compiler vendor. In addition, GNAT already gives a warning if no corresponding
accept statement for a declare task entry. GNAT, you are great!

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

From: Randy Brukardt
Sent: Monday, October 15, 2001  8:22 PM

> NOTES
> (22) A task entry has corresponding accept_statements (zero or more),
whereas a
> protected entry has a corresponding entry_body (exactly one).
>
> I would like to suggest to rephrase notes 22 as shown below

Umm, a note has no normative meaning. The rules which lead to the note are
elsewhere. You would need to change the original rules as well as the note.
(BTW, the paragraph reference in your message header is wrong, it ought to
be "9.5.2(27)".

In this case, it is really an absence of rules that lead to this result.
Task entries are not "completed", as subprograms and protected entries are.
This is because there can be many accepts for a particular entry. Writing a
rule with the effect you want would be rather tricky (we certainly don't
want to make any useful programs to be illegal). Something similar to 6.5(5)
might work, but the need to include parameter profiles would complicate the
rule. Dunno if it is worth the danger. (There are those who find 6.5(5) to
be limiting during prototyping.)

> In addition, GNAT already gives a warning if no corresponding
> accept statement for a declare task entry. GNAT, you are great!

GNAT also gives a warning if there is a way to exit a function without
executing a return statement. We got hundreds of those in Claw, from code
like:

    Result := <API call>;
    if Result = Error then
        raise Claw.Windows_Error;
    else
        return <expression involving Result>;
    end if;

Sometimes, such warnings *aren't* helpful!

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

From: Robert Dewar
Sent: Monday, October 15, 2001  8:51 PM

<<GNAT also gives a warning if there is a way to exit a function without
executing a return statement. ...>>

This is quite false, GNAT does not give a warning for the above code. I
don't know what Randy is talking about, but this particular example (which
is obviously not an exact quote) does not give any warning!

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

From: Randy Brukardt
Sent: Monday, October 15, 2001  9:21 PM

Well, it does for me (GNAT 3.14a1). We changed all of the many places that
we got warnings to eliminate them. I just put one of them back to
experiment, and I got:

Compiling: claw-static.adb (source file time stamp: 2001-10-16 02:15:50)

   670.                 Claw.Raise_Windows_Error;
                            |
        >>> warning: "return" statement missing following this statement
        >>> warning: Program_Error may be raised at run time

Ah...I see the difference. We use a subprogram to actually raise the
exception, because we need to construct an appropriate exception message
(and we didn't want hundreds of copies of that code in user's programs). But
my original comment stands...

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

From: Robert Dewar
Sent: Monday, October 15, 2001  9:26 PM

If Claw.Raise_Windows_Error can never return, then pragma No_Return should
be used, otherwise of course the error message is quite legitimate.

By the way, pragma No_Return is a good candidate for semi-standardization.

If you don't want to use pragma No_Return , then the proper way to suppress
this message is to put an explicit raise Program_Error after the call,
which makes it clear that you never expect control to return that way.
That will also suppress the message.

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

From: Robert Duff
Sent: Tuesday, October 16, 2001  10:31 AM

> By the way, pragma No_Return is a good candidate for semi-standardization.

I agree.  It makes the warnings much more useful, by eliminating most
bogus ones.

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

From: Robert Dewar
Sent: Tuesday, October 16, 2001  7:06 PM

And improves the code, by eliminating junk raises
And allows improved diagnosing of dead code following the call

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

From: Arthur Evans Jr
Sent: Tuesday, October 16, 2001  10:12 AM

At 20:22 -0500 2001.10.15, Randy Brukardt wrote:

>GNAT also gives a warning if there is a way to exit a function without
>executing a return statement. We got hundreds of those in Claw, from code
>like:
>
>     Result := <API call>;
>     if Result = Error then
>         raise Claw.Windows_Error;
>     else
>         return <expression involving Result>;
>     end if;
>
>Sometimes, such warnings *aren't* helpful!

There followed an instructive discussion between Randy and Robert.
Let me approach the matter differently.

Because the successor of the 'raise' statement is never the next
statement in the listing, you can reframe the fragment like this
without changing the effect:

     Result := <API call>;
     if Result = Error then
         raise Claw.Windows_Error;
     end if;
     return <expression involving Result>;

Of course if you write it this way, or even if you call a procedure
to raise the error and neglect to use 'pragma NoReturn' on that
procedure, GNAT won't complain about leaving the function without
a return.

However, I write this note because this is an example of a
guideline I've often thought about: Is it bad taste to have 'else'
follow some statement whose execution is never followed by the next
statement?

Consider

     if <something> then
         return <something else>
     else
         [lengthy sequence of statements]
     end if

I think it reads better to write

     if <something> then
         return <something else>
     end if
     [lengthy sequence of statements]

Any opinions?

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

From: Ted Baker
Sent: Thursday, October 18, 2001  7:05 AM

I agree with you.  The latter is better.

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

From: David Emery
Sent: Thursday, October 18, 2001 12:23 PM

What I prefer is adding comments to make things clear:

	if <something> then
		return <something else>;
  	end if;  -- <something>

	-- if we get here then it's not <something>
	[lengthy sequence of statements]

Although I've more often done the following (notice comments)

	If <something> then
		[bunch of statements]
	else -- not <something>
		[lots more statements]
	end if;  -- <something>

And as a rule of thumb, if either [bunch of statements] or
[lots more statements] are more than a page, I'll consider
making a nested subprogram to encapsulate the linear
sequence of statements, to make the control flow more clear:

	if <something> then
		first_bunch_of_statements;
	else -- not <something>
		second_bunch_of_statements;
	end if; -- <something>

I also tend to lean on pretty-printing/indentation to make
the control flow comb a little clearer.  But this only works
about 2-3 levels deep max on a single page or maybe 2 pages max.

But good style is the opinion of the ranking person reading the
code :-)

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

From: Robert Dewar
Sent: Friday, October 19, 2001  6:29 AM

Can I suggest that discussions of style of if statements are wildly off
topic for this list, and encourage people to stay on the subject. This
is hardly a general chat list :-)

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

From: Randy Brukardt
Sent: Tuesday, October 16, 2001  1:06 PM

> If Claw.Raise_Windows_Error can never return, then pragma No_Return should
> be used, otherwise of course the error message is quite legitimate.

Ah, GNAT has a pragma for that? We never looked at the GNAT-specific pragmas
when working on Claw, as it needs to work with all compilers. (Of course, a
pragma can be given anyway, it should just be a warning on other compilers).

> By the way, pragma No_Return is a good candidate for
> semi-standardization.

Sounds like it to me.

> If you don't want to use pragma No_Return, then the proper way to suppress
> this message is to put an explicit raise Program_Error after the call,
> which makes it clear that you never expect control to return that way.
> That will also suppress the message.

Well, we rearranged the code so that the return came after the if statement.
It was memorable because we had to do it in a hundred or so places (and it
pops up again from time to time). I've concluded that the code rearrangement
was for the better anyway, as slightly less code should be generated (there
would otherwise be a need for the code to raise Program_Error).

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

From: Robert Dewar
Sent: Tuesday, October 16, 2001  3:03 PM

<<Well, we rearranged the code so that the return came after the if statement.
It was memorable because we had to do it in a hundred or so places (and it
pops up again from time to time). I've concluded that the code rearrangement
was for the better anyway, as slightly less code should be generated (there
would otherwise be a need for the code to raise Program_Error).>>

Of course no such code is generated if you use pragma No_Return in GNAT.

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

From: Anh Vo
Sent: Tuesday, October 16, 2001  8:02 AM

Yes, I should have pointed out the rules instead of notes. Any way, it does not
make sense that declared entry could have no corresponding accept statement.
Then, task entry has no value, or it is a dead code. However, dead code does
not cause task deadlock. But, dead task entry code does. Therefore, it is much
danger not to change it since it costs time, money and headache.

I do not quite understand why it is tricky to write a rule requiring that there
is at least one corresponding accept statement for each declared entry. In
fact, why is it easy to write a rule requiring that there is one body
subprogram for one or none spec. subprogram?

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

From: Pascal Leroy
Sent: Tuesday, October 16, 2001  1:46 PM

> I do not quite understand why it is tricky to write a rule requiring that
> there is at least one corresponding accept statement for each declared entry.

If you want to understand this, I suggest that you try to write such a rule.
It's not impossible, but it's delicate.  You cannot rely on the rules for
completion, because there can be more than one accept statement for a given
entry.  And you have to be cautious with entry families.

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

From: Robert Dewar
Sent: Tuesday, October 16, 2001  1:01 PM

I find this not worth bothering about, at most a warning is appropriate. I
don't like rules of this nature in the language (an example is the silly
rule that functions must contain at least one return). If compilers consider
it an issue they can generate warnings, but why introduce a non-upwards
compatible change that does not add to expressive power?

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

From: Anh Vo
Sent: Tuesday, October 16, 2001  11:50 AM

I disagree. Can compiler vendors guaranteed to give warnings in this case?
Certainly, not. In fact, some compilers do and some do not. Even warning given
by the compilers, one now relies the compilers instead of the rules of the
language. That is not expressive power.

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

From: Robert Dewar
Sent: Tuesday, October 16, 2001  3:04 PM

So if a vendor does not even consider this issue important enough to
generate a warning (translation: their customers do not consider this
an important issue), then why on earth would the ARG be in the business
of decreeing that this be an error. As I said, rules that are basically
style rules seem a bad idea to me in any case.

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

From: Anh Vo
Sent: Thursday, October 18, 2001  6:58 PM

Warnings are given by at least two compilers. Therefore, it was considered
important by these compiler vendors. GNAT is one them.

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

From: Robert Dewar
Sent: Friday, October 19, 2001  9:58 AM

Important enough to give a warning, but the point of warnings is to warn that
something *might* be an error. Making this into an error would be a
non upwards compatible change that we would oppose. The burden for
non-upwards compatible changes should be considered VERY heavy.

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

From: Jean-Pierre Rosen
Sent: Tuesday, October 16, 2001  12:48 AM

> Yes, I should have pointed out the rules instead of notes. Any way,
> it does not make sense that declared entry could have no corresponding
> accept statement.

Actually, it is quite useful in at least one case. How do you wait for a task
to terminate, and be sure that it works in all cases, even if the task is
aborted, and without race condition? Easy, call an entry of the task that is
never accepted, and catch Tasking_Error...

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

From: Ted Baker
Sent: Thursday, October 18, 2001  7:02 AM

| Yes, I should have pointed out the rules instead of notes. Any way, it does
| not make sense that declared entry could have no corresponding accept
| statement. Then, task entry has no value, or it is a dead code. However,
| dead code does not cause task deadlock. But, dead task entry code does.
| Therefore, it is much danger not to change it since it costs time, money and
| headache.

| I do not quite understand why it is tricky to write a rule requiring that
| there is at least one corresponding accept statement for each declared entry.
| In fact, why is it easy to write a rule requiring that there is one body
| subprogram for one or none spec. subprogram?

1) Such a rule would only catch the most obvious kind of error.  In real life
   with experienced programmers deadlocks occur for more subtle reasons.

2) There actually are situations where it is useful to have an
   entry with no accept, that can be used to block a task forever (or until
   it gets an asynchronous exception).

3) A compiler can always provide an advisory warning message about this case.

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



Questions? Ask the ACAA Technical Agent