Bug 12406 – Broken delegate closure

Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2014-03-18T17:56:00Z
Last change time
2015-06-17T21:02:53Z
Keywords
pull, wrong-code
Assigned to
nobody
Creator
lt.infiltrator

Comments

Comment #0 by lt.infiltrator — 2014-03-18T17:56:05Z
In some ((apparently) random and confusing) cases, a delegate's closure is broken, and seems to be influenced by completely unrelated pieces of code. http://dpaste.dzfl.pl/5f9ebc61274a ------------------------------------------------------------------------ import std.functional; import std.stdio; class UserInterface { void title(string title) { _messages = title; } /* Changing this to writeln(title) and removing display(), below, magically fixes it. */ string display() { writeln(_messages); stdout.flush; return readln; } string _messages; } class Screen { void addMessageSource(string delegate()) { } void addOption(Screen delegate() action) { _options ~= Option(action); } Screen execute(UserInterface ui) { ui.title(title); auto action = _options[0].action; ui.display; /* Removing this line magically fixes it. */ return action(); } this(string title) { this.title = title; } struct Option { Screen delegate() action; } string title; Option[] _options; } string printStatus(int) { return "Printing status"; } void configureScreen(Screen screen) { auto systemStatus = new Screen("System status"); int x; systemStatus.addMessageSource(&curry!(printStatus, x)); /* Removing this line magically fixes it. */ Screen renameName() { return new Screen("Rename system"); } Screen renameSelect() { auto ret = new Screen("Select system"); void addItem() { ret.addOption(&renameName); } /* Removing this line magically fixes it. */ ret.addOption(() => screen); /* The segfault occurs here. */ return ret; } screen.addOption(&renameSelect); } int main() { auto screen = new Screen("Systems screen"); configureScreen(screen); while(screen) screen = screen.execute(new UserInterface); return 0; }
Comment #1 by lt.infiltrator — 2015-01-23T14:01:39Z
Bug still exists in 2.065.
Comment #2 by dlang-bugzilla — 2015-01-23T15:09:40Z
Reduced: ////////////////////////////// test.d ////////////////////////////// struct Dg { Dg delegate() action; } void fn(void delegate()) { } Dg createDg() { int x; fn({ x++; }); // required Dg dg; Dg createDg2() { int x; void unusedFun() { x++; } // required //fn({x++;}); // workaround - force closure creation return Dg(() => dg); // lambda returns garbage instead of dg } return dg = Dg(&createDg2); } void main() { auto dg = createDg(); foreach (i; 0..10) dg = dg.action(); } //////////////////////////////////////////////////////////////////// As in the reduced example, you can work around this bug by forcing the compiler to create a closure for the inner function.
Comment #3 by dlang-bugzilla — 2015-01-23T16:15:55Z
Note: Above reduced test case requires -g
Comment #4 by k.hara.pg — 2015-03-24T12:57:28Z
Comment #5 by github-bugzilla — 2015-03-25T04:13:14Z
Commits pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/ceb20a25a55827d6b2644329839edf642557e552 fix Issue 12406 - Broken delegate closure https://github.com/D-Programming-Language/dmd/commit/d49c7dc77afe64c7f39683461e38a680a9fa2c04 Merge pull request #4513 from 9rnsr/fix12406 Issue 12406 - Broken delegate closure
Comment #6 by github-bugzilla — 2015-06-17T21:02:53Z