Bug 5191 – Combination of pure and nothrow result in a function that does nothing
Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
Linux
Creation time
2010-11-09T02:31:00Z
Last change time
2015-06-09T05:15:22Z
Keywords
patch, wrong-code
Assigned to
nobody
Creator
issues.dlang
Comments
Comment #0 by issues.dlang — 2010-11-09T02:31:20Z
import std.stdio;
struct Foo
{
void add(T)(T value) pure nothrow
{
this.value += value;
}
this(int value)
{
this.value = value;
}
int value;
}
void main()
{
auto foo = Foo(5);
assert(foo.value == 5);
foo.add(2);
writeln(foo.value);
assert(foo.value == 7);
foo.add(3);
writeln(foo.value);
assert(foo.value == 10);
foo.add(3);
writeln(foo.value);
assert(foo.value == 13);
}
If you remove either the pure _or_ the nothrow (or both) from add(), you get this output:
7
10
13
However, if add() is both pure and nothrow, then you get an assertion failure:
5
core.exception.AssertError@test(25): Assertion failure
----------------
./test(onAssertError+0x2e) [0x808d40e]
./test(_d_assertm+0x16) [0x8085536]
./test(void test.__assert(int)) [0x80828d6]
./test(_Dmain+0x43) [0x807f7a7]
./test(extern (C) int rt.dmain2.main(int, char**)) [0x8085746]
./test(extern (C) int rt.dmain2.main(int, char**)) [0x80856a0]
./test(extern (C) int rt.dmain2.main(int, char**)) [0x808578a]
./test(extern (C) int rt.dmain2.main(int, char**)) [0x80856a0]
./test(main+0x96) [0x8085646]
/usr/lib32/libc.so.6(__libc_start_main+0xe6) [0xf75d7c76]
./test() [0x807f6a1]
For some reason, the combination of pure and nothrow results in the function being a no-op. Personally, since I try to make as many functions nothrow and as many functions pure as possible, this is a serious fly in the ointment of both pure and nothrow.
Comment #1 by clugdbug — 2010-11-09T04:37:00Z
Nasty. It's because pure member functions are internally being marked as const somehow. That needs to be fixed. In DMD2.049, this code didn't compile.
Comment #2 by clugdbug — 2010-11-10T00:27:33Z
Extra test case (add to the end of the original test case):
---
void delegate (int) pure nothrow dg = &foo.add!(int);
dg(7);
assert(foo.value == 20);
--
PATCH: e2ir.c, callfunc(), line 294. To determine if a function is strongly pure, you need to look at the function declaration, not just the function type, since the 'this' parameter isn't part of the type.
-----
else if (ep)
{ /* Do not do "no side effect" calls if a hidden parameter is passed,
* as the return value is stored through the hidden parameter, which
* is a side effect.
*/
- e = el_bin((tf->purity == PUREstrong && tf->isnothrow && (retmethod != RETstack)) ?
+ e = el_bin(((fd ? fd->isPure() : tf->purity) == PUREstrong && tf->isnothrow && (retmethod != RETstack)) ?
OPcallns : OPcall,tyret,ec,ep);
if (tf->varargs)
e->Eflags |= EFLAGS_variadic;
}
else
- { e = el_una((tf->purity == PUREstrong && tf->isnothrow && (retmethod != RETstack)) ?
+ { e = el_una(((fd ? fd->isPure() : tf->purity) == PUREstrong && tf->isnothrow && (retmethod != RETstack)) ?
OPucallns : OPucall,tyret,ec);
Comment #3 by bearophile_hugs — 2010-11-26T14:42:08Z
*** Issue 5277 has been marked as a duplicate of this issue. ***
Comment #4 by dsimcha — 2010-11-29T06:37:58Z
Note that inlining must be turned off for this test case to fail.