[Issue 21626] New: foreach create reference to rvalue tuple returned by front
    d-bugmail at puremagic.com 
    d-bugmail at puremagic.com
       
    Wed Feb 10 13:25:24 UTC 2021
    
    
  
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 at puremagic.com
          Reporter: submada at 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);
}
--
    
    
More information about the Digitalmars-d-bugs
mailing list