digitalmars.D.bugs - [Issue 21626] New: foreach create reference to rvalue tuple returned
- d-bugmail puremagic.com (90/90) Feb 10 2021 https://issues.dlang.org/show_bug.cgi?id=21626
https://issues.dlang.org/show_bug.cgi?id=21626 Issue ID: 21626 Summary: foreach create reference to rvalue tuple returned by front Product: D Version: D2 Hardware: All OS: All Status: NEW Severity: major Priority: P1 Component: dmd Assignee: nobody puremagic.com Reporter: submada gmail.com If range return rvalue tuple from front and foreach unpack tuple then temporary value to front is ref and after leaving scope destructor is not called: import std.range; import std.stdio; import std.typecons; int created, destroyed; ///struct count destructions and constructions struct S{ int val; disable this(); this(int val) { this.val = val; created++; } this(ref inout const typeof(this) rhs)inout { this.val = rhs.val; created++; } ~this() { destroyed++; } } //range, for each call of front return rvalue Tuple!(S, S) struct Generator(T){ int n; this(int n){ this.n = n; } property Tuple!(T, T) front(){ return tuple(T(n), T(n)); } property void popFront(){ n -= 1; } property bool empty()const{ return n < 1; } } ///This work OK: void test_A(){ foreach(s; Generator!S(10)){ assert(s[0].val == s[1].val); } assert(created == destroyed); } ///This fail: void test_B(){ foreach(s1, s2; Generator!S(10)){ assert(s1.val == s2.val); } writeln(": created ", created, " vs destroyed ", destroyed); ///created != destroyed assert(created == destroyed); ///FAIL!! } void main() { test_A(); test_B(); } test_B AST: void test_B() { { Generator!(S) __r101 = __r101 = 0 , __r101.this(10); for (; !__r101.empty(); __r101.popFront()) { ref Tuple!(S, S) __front102 = __r101.front(); ///PROBLEM! reference to rvalue, destructor is not called! ref S s1 = __front102.__expand_field_0; ref S s2 = __front102.__expand_field_1; assert(s1.val == s2.val); } } writeln(": created ", created, " vs destroyed ", destroyed); assert(created == destroyed); } --
Feb 10 2021