D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 3020 - No description is given why function may not be nothrow
Summary: No description is given why function may not be nothrow
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86 Windows
: P2 critical
Assignee: No Owner
URL:
Keywords: diagnostic, patch
Depends on:
Blocks:
 
Reported: 2009-05-23 03:08 UTC by Koroskin Denis
Modified: 2014-02-14 20:35 UTC (History)
5 users (show)

See Also:


Attachments
patch against svn 724 (32.79 KB, patch)
2010-10-22 17:16 UTC, Don
Details | Diff

Note You need to log in before you can comment on or make changes to this issue.
Description Koroskin Denis 2009-05-23 03:08:29 UTC
import std.stdio;

int foo(int i, int j) nothrow
{
	return i + j;
}

int bar() nothrow
{
	return 0;
}

void test() nothrow
{
	int x = bar();
	int y = foo(x, x);
	writefln("%d, %d", x, y);
}

void main()
{
	test();
}

Expected output:
test.d(13): Error: function test.test 'test' is nothrow yet writefln at test.d(17) may throw

Actual output:
test.d(13): Error: function test.test 'test' is nothrow yet may throw

Rising its severity because the feature is barely usable without appropriate error messages.
Comment 1 Jonathan M Davis 2010-09-17 23:38:10 UTC
I'm not sure that I agree that this bug is "critical," since dmd works fine with this bug. It's just highly annoying. But as it is highly annoying, it would definitely be nice to have this fixed. If you're trying to make your code use nothrow as much as possible (which I would think would be ideal, just as you'd try and use const as much as possible), this bug really gets in the way. It's not fatal, but it sure is annoying.
Comment 2 bearophile_hugs 2010-09-19 17:46:06 UTC
This isn't a critical bug. There are FAR worse bugs in DMD that are rated as normal bugs.
Comment 3 Don 2010-10-22 17:16:07 UTC
Created attachment 790 [details]
patch against svn 724

This is a big patch, but it's very simple. When checking for the return type of functions, the info about whether it is a nothrow function is passed as a parameter. If it throws from inside a nothrow function, it generates an error message.
Comment 4 Don 2010-10-22 17:23:09 UTC
For the initial test case, the error messages are:

test.d(17): Error: writefln is not nothrow
test0.d(13): Error: function test0.test 'test' is nothrow yet may throw

Another example:
=======
import core.exception;

void foo() nothrow
{
    try {
	throw new Exception("xxx");		
    } catch(Exception e) {
	auto z = new int;
	throw e;
    }
}
----
test.d(8): Error: 'new int' may throw OutOfMemoryError
test.d(9): Error: object.Exception is thrown but not caught
test.d(3): Error: function test0.foo 'foo' is nothrow yet may throw
Comment 5 Walter Bright 2010-10-29 03:21:11 UTC
Out of memory errors should be allowed inside nothrow.

Also, I suspect it would be good to disallow:

try
{
   ...
}
catch (Exception e)
{
   /* nothing here */
}

where all exceptions are swallowed and ignored. This kind of thing happens in Java to work around exception specifications, but I don't see a need for it here. Of course, there would still be ways to swallow & ignore (just put in a call to a do-nothing function), but such shouldn't be easy.

What do you think?
Comment 6 Jonathan M Davis 2010-10-29 03:37:35 UTC
There are plenty of cases where you know that a function will never throw but it's not nothrow (perhaps because it can throw in other circumstances), and you're forced to catch the Exception anyway (probably because you're in a nothrow function). Personally, I use assert(0) for such cases.

As long as disallowing empty catch blocks is really for _empty_ catch blocks (or catch blocks with only a comment), I don't mind. But there are definitely cases where you want to eat an exception or where there should never be one but you have to have a try-catch anyway.
Comment 7 Don 2010-10-29 05:30:34 UTC
(In reply to comment #5)
> Out of memory errors should be allowed inside nothrow.

Good. I think so too. That will make nothrow much more useful.
In the existing compiler, they are disallowed. 
( void foo() nothrow { auto x = new int; }  won't compile).
I just added error messages to specify why it was being disallowed.

It sounds as though the check for nothrow violations should be separated from the code which determines if a statement can throw. That is, for 'new' and for asm, we assume that it can throw. But, if it's in a nothrow function, we trust the programmer.
Then, what happens if an out of memory condition happens in a nothrow function? Is the program simply terminated?

> 
> Also, I suspect it would be good to disallow:
> 
> try
> {
>    ...
> }
> catch (Exception e)
> {
>    /* nothing here */
> }
> 
> where all exceptions are swallowed and ignored. This kind of thing happens in
> Java to work around exception specifications, but I don't see a need for it
> here. Of course, there would still be ways to swallow & ignore (just put in a
> call to a do-nothing function), but such shouldn't be easy.
> 
> What do you think?

Dunno. It's certainly bad style.
Comment 8 Walter Bright 2010-10-29 10:29:39 UTC
(In reply to comment #7)
> In the existing compiler, they are disallowed. 

That's a bug.

> ( void foo() nothrow { auto x = new int; }  won't compile).
> I just added error messages to specify why it was being disallowed.
> It sounds as though the check for nothrow violations should be separated from
> the code which determines if a statement can throw. That is, for 'new' and for
> asm, we assume that it can throw. But, if it's in a nothrow function, we trust
> the programmer.
> Then, what happens if an out of memory condition happens in a nothrow function?
> Is the program simply terminated?

Yes.
Comment 9 Andrei Alexandrescu 2010-10-29 11:11:26 UTC
(In reply to comment #5)
> Out of memory errors should be allowed inside nothrow.
> 
> Also, I suspect it would be good to disallow:
> 
> try
> {
>    ...
> }
> catch (Exception e)
> {
>    /* nothing here */
> }
> 
> where all exceptions are swallowed and ignored. This kind of thing happens in
> Java to work around exception specifications, but I don't see a need for it
> here. Of course, there would still be ways to swallow & ignore (just put in a
> call to a do-nothing function), but such shouldn't be easy.
> 
> What do you think?

There are plenty of cases when you want to swallow exceptions, and it's highly unlikely that anyone would write such a pattern by mistake. So let's keep allowing it. At best, the compiler could protest that "e" is not being used and ask for a nameless catch.
Comment 10 Don 2010-10-29 21:42:16 UTC
Fixed svn 736.