Bug 8269 – The 'with statement' does not observe temporary object lifetime

Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P3
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-06-19T12:23:00Z
Last change time
2014-08-10T08:56:44Z
Keywords
bounty, pull, wrong-code
Assigned to
yebblies
Creator
acehreli

Comments

Comment #0 by acehreli — 2012-06-19T12:23:56Z
The spec at http://dlang.org/statement.html#WithStatement says: <quote> The WithStatement with (expression) { ... ident; } is semantically equivalent to: { Object tmp; tmp = expression; ... tmp.ident; } </quote> Unfortunately, the anonymous object in the following code is destroyed even before entering the 'with' scope: import std.stdio; struct S { this(int i = 0) { writeln("constructed"); } ~this() { writeln("destructed"); } } void main() { with(S(1)) { writeln("inside 'with' statement"); } } Observed output: constructed destructed inside 'with' statement Expected output: constructed inside 'with' statement destructed Ali
Comment #1 by andrej.mitrovich — 2013-02-08T14:08:31Z
*** Issue 9145 has been marked as a duplicate of this issue. ***
Comment #2 by andrej.mitrovich — 2013-02-08T14:08:58Z
Slightly renamed title to make it more searchable.
Comment #3 by andrej.mitrovich — 2013-03-23T05:18:18Z
(In reply to comment #0) > The spec at > > http://dlang.org/statement.html#WithStatement > > says: > > <quote> > The WithStatement > with (expression) > { > ... > ident; > } > is semantically equivalent to: > { > Object tmp; > tmp = expression; > ... > tmp.ident; > } > </quote> What it does end up doing is inject an initializer and a comma expression, and then takes the address of that. It's totally bizarre..
Comment #4 by code — 2013-10-25T09:57:03Z
*** Issue 11351 has been marked as a duplicate of this issue. ***
Comment #5 by verylonglogin.reg — 2014-07-11T10:21:49Z
Smaller testcase: --- struct S { bool alive = true; ~this() { alive = false; } } void main() { with(S()) // <-- `S` is created and destructed here assert(alive); // fails } --- This is a major issue as it breaks RAII.
Comment #6 by andrei — 2014-07-29T18:36:14Z
@yebblies: why did you remove the "preapproved" tag?
Comment #7 by yebblies — 2014-07-30T05:52:38Z
(In reply to Andrei Alexandrescu from comment #6) > @yebblies: why did you remove the "preapproved" tag? I don't see the point of it on a wrong code bug. Either the bug is valid and it will be fixed, or it isn't and it won't.
Comment #8 by andrei — 2014-07-30T14:23:04Z
I see - fine. I was hoping to boost its visibility :o).
Comment #9 by yebblies — 2014-07-30T14:37:13Z
(In reply to Andrei Alexandrescu from comment #8) > I see - fine. I was hoping to boost its visibility :o). I can't speak for the other dmd contributors, but I never look at the preapproved list. I will look at the ice and wrong-code lists when I'm in that kind of mood. If you really want to boost its profile, tou could try putting a big bounty on it :D This is actually a perfect example of a good bug for a bounty - it is non-controversial, and has a small, well-defined scope. It's almost entirely debugging and implementation. Anyway, it's next on my list, assuming I don't get distracted. As Andrej noted the implementation of 'with' is a big weird and needs some work.
Comment #10 by andrei — 2014-08-08T20:37:16Z
Comment #11 by blah38621 — 2014-08-08T20:38:53Z
I would suspect that this is likely because of how the with statement currently expands itself, although it's certainly possible that it's e2ir (though I don't think it actually is present at the e2ir layer, was about to check that)
Comment #12 by yebblies — 2014-08-09T06:04:24Z
It is how it expands itself. with(exp) {...} gets re-written to with(auto tmp = exp, tmp) {...} and then with(auto withptr = &(auto tmp = exp, tmp)) {...} which ends up looking like auto withptr = &(auto tmp = exp, tmp) ... in the glue layer. Since tmp is local to the expression, the dtor code is inserted right after it. https://github.com/D-Programming-Language/dmd/pull/3855
Comment #13 by damianday — 2014-08-09T10:20:59Z
Why would the with statement be creating a temporary in the first place? It seems terribly inefficient, surely it can just alias the original object and be done with it?
Comment #14 by yebblies — 2014-08-09T11:18:42Z
(In reply to Damian from comment #13) > Why would the with statement be creating a temporary in the first place? It > seems terribly inefficient, surely it can just alias the original object and > be done with it? It does when it can, but it can't when the with argument is an rvalue. eg Struct generateStructForMe() { ... } with(generateStructForMe()) { auto x = member1 + member2; } You want this to expand to (and in lvalue cases it will) auto withptr = &generateStructForMe(); auto x = withptr.member1 + withptr.member2; But this can't work, because the struct has to be stored somewhere before you can take its address. The struct literals in these examples are also rvalues and work the same way. Class references and struct pointers do not have this problem an can be copied freely.
Comment #15 by blah38621 — 2014-08-09T19:23:30Z
What does it do about postblits in this case?
Comment #16 by yebblies — 2014-08-10T07:36:44Z
(In reply to Orvid King from comment #15) > What does it do about postblits in this case? The same thing that happens with auto tmp = someRvalue(); with(tmp) { }
Comment #17 by github-bugzilla — 2014-08-10T08:56:44Z
Commits pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/4321a856bd1e3ed1aa0fe5e613a658ad192c9e86 Fix Issue 8269 - The 'with statement' does not observe temporary object lifetime https://github.com/D-Programming-Language/dmd/commit/839f2e1bc929ba3055c4d64c022a5f98fa7225c5 Merge pull request #3855 from yebblies/issue8269 Issue 8269 - The 'with statement' does not observe temporary object lifetime