www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 15328] New: Postblit not called

https://issues.dlang.org/show_bug.cgi?id=15328

          Issue ID: 15328
           Summary: Postblit not called
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: major
          Priority: P1
         Component: druntime
          Assignee: nobody puremagic.com
          Reporter: andrei erdani.com

I have a rather complicated repro that could use fresh eyes for simplification.
The gist of it is the the function Range save() { return this; } does not call
the postblit.

struct List(T)
{
    import std.traits;

    private struct Node
    {
        T payload;
        Node* next;
        uint refs;
    }

    // layout {
    private const(Node)* root;
    // } layout

    private  trusted static void incRef(const Node* n)
    {
        if (n) ++*(cast(uint*) &(n.refs));
    }

    private  trusted static void decRefUnchecked(const Node* n)
    {
        assert(n && n.refs > 1);
        --*(cast(uint*) &(n.refs));
    }

    // Entry point, decRef and destroy+deallocate if down to zero
    private static void decRef(const Node* n)
    {
        assert(n);
        if (n.refs > 1)
        {
            decRefUnchecked(n);
            return;
        }
        static if (hasMember!(T, "__dtor"))
            n.payload.__dtor();
    }

    this(this)
    {
        incRef(root);
    }

    ~this()
    {
        for (auto n = root; n;)
        {
            if (n.refs > 1)
            {
                decRefUnchecked(n);
                return;
            }
            auto goner = n;
            n = n.next;
            static if (hasMember!(T, "__dtor"))
                goner.payload.__dtor();
        }
    }

    private this(const Node* n)
    {
        root = n;
    }

    /**
     * Returns a new $(D List) consisting of $(D head) followed by the contents
of $(D this).
     * Complexity: $(BIGOH n).
     */
    List opBinaryRight(string op)(T head)
        if (op == "~")
    {
        List result;
        import std.conv : emplace;
        auto n = new const Node(head, root, 1);
        incRef(root);
        result.root = n;
        return result;
    }

    auto opSlice() inout
    {
        static struct Range
        {
            // layout {
            private const(Node)* root;
            // } layout 

            this(this)
            {
                incRef(root);
            }

            ~this()
            {
                if (!root) return;
                assert(root.refs >= 1);
                decRef(root);
            }

            Range save()
            {
                return this;
            }
        }
        incRef(root);
        auto result = Range(root);
        return result;
    }
}

unittest
{
    auto lst = 1 ~ (2 ~ (3 ~ List!(immutable int)()));
    auto lst2 = 42 ~ lst;
    auto range = lst2[];
    assert(lst.root.refs == 2);
    auto range1 = range.save;
    assert(lst.root.refs == 3); // fails
}

void main() {}

--
Nov 13 2015