Bug 21586 – Struct dtor is called twice if struct is created inside ternary operator
Status
RESOLVED
Resolution
FIXED
Severity
critical
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2021-01-26T22:27:45Z
Last change time
2021-02-13T12:29:59Z
Keywords
pull
Assigned to
No Owner
Creator
Temtaime
Comments
Comment #0 by temtaime — 2021-01-26T22:27:45Z
import std.stdio;
struct S
{
this(int arg)
{
a = arg;
writeln(`this`);
}
~this()
{
writeln(`~this `, a);
}
int a;
}
void main()
{
auto s = true ? S(1) : S(0);
}
Outputs:
this
~this 1
~this 1
Should:
this
~this 1
Comment #1 by moonlightsentinel — 2021-01-26T23:38:09Z
Modified:
extern (C) int printf(scope const char*, ...);
struct S
{
this(int arg)
{
a = arg;
printf("this(%d), this = %p\n", a, &this);
}
~this()
{
printf("~this(%d), this = %p\n", a, &this);
}
int a;
}
void main()
{
auto s = true ? S(1) : S(0);
printf("main\n");
}
----
this(1), this = 0x7fff3b745b88
~this(1), this = 0x7fff3b745b88
main
~this(1), this = 0x7fff3b745b98
---
So there's only one dtor call for the temporary created inside of the ternary operator and another call for the variable s at the end of main.
Comment #2 by razvan.nitu1305 — 2021-01-27T09:33:11Z
(In reply to Temtaime from comment #0)
As moonlightsentinel highlighted, the variable is destroyed only once. The code in main is roughly translated to this:
void main()
{
S tmp;
auto s = (true ? tmp = S(1) : tmp = S(0); tmp);
tmp.__dtor;
s.__dtor;
}
This is the intended behavior. Closing as invalid.
Comment #3 by japplegame — 2021-01-27T10:27:54Z
But if you add a copy constructor to the structure, no temporary copy is created.
It's weird, but acceptable.
Comment #4 by boris2.9 — 2021-01-27T11:45:50Z
The temporary variable also disappears when there's a postblit.
AST generated when a postblit or copy constructor is present:
S s = (true) ? s = 0 , s.this(1) : (s = 0 , s.this(0));
In the original case:
S s = (true) ? (S(0)).this(1) : (S(0)).this(0);
Looks like a frontend bad decision, there's no reason to not generate the equivalent code to a simple assignment. For example:
S s = S(1);
generates:
S s = s = 0 , s.this(1);
Comment #5 by dlang-bot — 2021-01-28T11:56:07Z
@BorisCarvajal created dlang/dmd pull request #12163 "Fix Issue 21586 - Struct dtor is called twice if struct is created in…" fixing this issue:
- Fix Issue 21586 - Struct dtor is called twice if struct is created inside ternary operator
https://github.com/dlang/dmd/pull/12163
Comment #6 by dlang-bot — 2021-01-31T09:12:51Z
dlang/dmd pull request #12163 "Fix Issue 21586 - Struct dtor is called twice if struct is created in…" was merged into stable:
- 9ca0687a06db987e12581ca216445976b559fae4 by Boris Carvajal:
Fix Issue 21586 - Struct dtor is called twice if struct is created inside ternary operator
https://github.com/dlang/dmd/pull/12163
Comment #7 by dlang-bot — 2021-02-13T12:29:59Z
dlang/dmd pull request #12195 "Merge stable" was merged into master:
- a3b4319bd1aa9a92db46bf61bcc2feb2ab668b7f by Boris Carvajal:
Fix Issue 21586 - Struct dtor is called twice if struct is created inside ternary operator (#12163)
https://github.com/dlang/dmd/pull/12195