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.
Comment #5 by bugzilla — 2010-12-04T19:35:21Z