digitalmars.D - Destructors and static array assignment
- David Nadlinger (31/31) Jul 20 2015 Hi all,
- Jonathan M Davis (19/24) Jul 20 2015 Purposeful or not, I don't see how it could be anything other
- Benjamin Thaut (7/33) Jul 20 2015 This bug with "out" and structs is very old:
- Jonathan M Davis (24/28) Jul 20 2015 That bug report certainly paints a more complicated and
- Kenji Hara via Digitalmars-d (13/41) Jul 20 2015 At least there's a dmd bug.
- Kenji Hara via Digitalmars-d (4/12) Jul 20 2015 I filed a new wrong-code issue.
Hi all, I was about to fix an issue with postblits/destructors in LDC when I stumbled upon the following vexing behaviour in DMD (both 2.067.1 and master): --- uint dtorCount; struct S { uint x; void opAssign(const ref S rhs) { assert(false, "Not called"); } ~this() { ++dtorCount; } } void main() { S[2] a; a[0].x = 42; a = a.init; assert(a[0].x == 0); // as expected the value has been reset assert(dtorCount == 0); // Passes?!? } --- I would have expected this to either call opAssign or to destruct the instance, blit the init value, and call any postblits. However, as you can see neither the dtor nor opAssign are executed. If I add a postblit to S, then suddenly the dtor is invoked too. Am I missing something here, or is this a major bug in struct lifetime handling? I understand why this happens from the DMD source, but it almost seems like it was deliberately written this way; thus the question. — David
Jul 20 2015
On Monday, 20 July 2015 at 14:18:33 UTC, David Nadlinger wrote:Am I missing something here, or is this a major bug in struct lifetime handling? I understand why this happens from the DMD source, but it almost seems like it was deliberately written this way; thus the question.Purposeful or not, I don't see how it could be anything other than a bug. It fundamentally breaks your ability to control what's going on with the construction or destruction of an object. And a quick check seems to indicate that out parameters have the same problem. If I add this function void foo(out S s) { } and then this to the end of main { S s; foo(s); } it fails to hit the assertion. The dtorCount in 1, which I think is correct, since the out param is a reference to s and thus shouldn't destroy it, but it _should_ assign to it, and it looks like it's just bitblitting S.init rather than assigning it S.init. - Jonathan M Davis
Jul 20 2015
On Monday, 20 July 2015 at 14:51:57 UTC, Jonathan M Davis wrote:On Monday, 20 July 2015 at 14:18:33 UTC, David Nadlinger wrote:This bug with "out" and structs is very old: https://issues.dlang.org/show_bug.cgi?id=6186 It even has 26 votes, but it doesn't seem to be important enough to be fixed. Kind Regards Benjamin ThautAm I missing something here, or is this a major bug in struct lifetime handling? I understand why this happens from the DMD source, but it almost seems like it was deliberately written this way; thus the question.Purposeful or not, I don't see how it could be anything other than a bug. It fundamentally breaks your ability to control what's going on with the construction or destruction of an object. And a quick check seems to indicate that out parameters have the same problem. If I add this function void foo(out S s) { } and then this to the end of main { S s; foo(s); } it fails to hit the assertion. The dtorCount in 1, which I think is correct, since the out param is a reference to s and thus shouldn't destroy it, but it _should_ assign to it, and it looks like it's just bitblitting S.init rather than assigning it S.init. - Jonathan M Davis
Jul 20 2015
On Monday, 20 July 2015 at 14:56:45 UTC, Benjamin Thaut wrote:This bug with "out" and structs is very old: https://issues.dlang.org/show_bug.cgi?id=6186 It even has 26 votes, but it doesn't seem to be important enough to be fixed.That bug report certainly paints a more complicated and controversial picture on the issue than I would have expected. But I think that the issue is pretty much the same as what David's bringing up. Certainly, having S[2] a; a = S.init; and void foo(out S s) {} S s; foo(a); not be consistent seems like a bad idea. In both cases, we're dealing with setting the variable to its init value, and having that not be the same in all circumstances just seems like it's begging for trouble... The only way that I can see that they would reasonably be different would be if out were simply disallowing the variable to be anything other than its init value, which might make sense, but it wouldn't make sense when explicitly assigning the init value to a variable. So, making it so that out requires that the variable be its init value is really just sidestepping the issue with out while still leaving it elsewhere, so sidestepping it with out doesn't really save us from having to solve the problem. - Jonathan M Davis
Jul 20 2015
At least there's a dmd bug. For such static array assignment, dmd should use druntime function, but instead plain memory copy operation used. https://github.com/D-Programming-Language/dmd/blob/master/src/e2ir.c#L2920 https://github.com/D-Programming-Language/dmd/blob/master/src/e2ir.c#L2945 And, even after the bug is fixed, I think it's debatable behavior whether an element-wise assignment should call opAssign on each elements, because it can be a kind of optimization. Related issue: https://issues.dlang.org/show_bug.cgi?id=3D8931 Kenji Hara 2015-07-20 23:18 GMT+09:00 David Nadlinger via Digitalmars-d < digitalmars-d puremagic.com>:Hi all, I was about to fix an issue with postblits/destructors in LDC when I stumbled upon the following vexing behaviour in DMD (both 2.067.1 and master): --- uint dtorCount; struct S { uint x; void opAssign(const ref S rhs) { assert(false, "Not called"); } ~this() { ++dtorCount; } } void main() { S[2] a; a[0].x =3D 42; a =3D a.init; assert(a[0].x =3D=3D 0); // as expected the value has been reset assert(dtorCount =3D=3D 0); // Passes?!? } --- I would have expected this to either call opAssign or to destruct the instance, blit the init value, and call any postblits. However, as you ca=nsee neither the dtor nor opAssign are executed. If I add a postblit to S, then suddenly the dtor is invoked too. Am I missing something here, or is this a major bug in struct lifetime handling? I understand why this happens from the DMD source, but it almost seems like it was deliberately written this way; thus the question. =E2=80=94 David
Jul 20 2015
2015-07-20 23:52 GMT+09:00 Kenji Hara <k.hara.pg gmail.com>:At least there's a dmd bug. For such static array assignment, dmd should use druntime function, but instead plain memory copy operation used. https://github.com/D-Programming-Language/dmd/blob/master/src/e2ir.c#L2920 https://github.com/D-Programming-Language/dmd/blob/master/src/e2ir.c#L2945 And, even after the bug is fixed, I think it's debatable behavior whether an element-wise assignment should call opAssign on each elements, because it can be a kind of optimization.I filed a new wrong-code issue. https://issues.dlang.org/show_bug.cgi?id=14815 Kenji Hara
Jul 20 2015