import std.stdio;
struct Foo {
int val;
this(int val) {
writefln("%s.this(int)", val);
this.val = val;
}
this(this) {
writefln("%s.this(this)", val);
this.val = val;
}
~this() {
writefln("%s.~this()", val);
this.val = val;
}
}
struct Bar {
Foo foo;
this(Foo foo, bool) { this.foo = foo; }
}
bool fun(bool val) { return !val; }
auto genBar(bool flag) {
return flag ? Bar() : Bar(Foo(10), fun(!flag));
}
void main(string[] args) {
auto bar = genBar(args.length == 0);
}
Compiler generates extra destructor call:
10.this(int)
10.this(this)
10.~this()
10.~this()
10.~this()
If we slightly change function genBar:
auto genBar(bool flag) {
auto a = flag ? Bar() : Bar(Foo(10), fun(!flag));
return a;
}
or
auto genBar(bool flag) {
return flag ? Bar() : Bar(Foo(10), false);
}
then output looks as expected:
10.this(int)
10.this(this)
10.~this()
10.~this()
Comment #1 by dlang-bugzilla — 2017-07-02T14:36:29Z
Same example with asserts replacing writelns, and checks based on simple reference counting:
struct Foo
{
int* rc;
this(int val)
{
rc = new int;
(*rc) = 1;
}
this(this)
{
(*rc)++;
}
~this()
{
if (rc)
{
assert(*rc > 0);
(*rc)--;
}
}
}
struct Bar
{
Foo foo;
this(Foo foo, bool)
{
this.foo = foo;
}
}
bool fun(bool val) { return !val; }
auto genBar(bool flag)
{
return flag ? Bar() : Bar(Foo(10), fun(!flag));
}
void main(string[] args)
{
auto bar = genBar(args.length == 0);
}
This appears to be a regression, as it worked before 2.052.
Introduced in https://github.com/dlang/dmd/commit/e764b3949ae0f95f8fc4d7d2e9114e29fee12493