Bug 15328 – Postblit not called

Status
RESOLVED
Resolution
INVALID
Severity
major
Priority
P1
Component
druntime
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-11-13T16:59:00Z
Last change time
2015-11-13T21:10:06Z
Assigned to
nobody
Creator
andrei

Comments

Comment #0 by andrei — 2015-11-13T16:59:33Z
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() {}
Comment #1 by public — 2015-11-13T17:13:13Z
Can it be RVO hitting?
Comment #2 by andrei — 2015-11-13T17:27:01Z
(In reply to Dicebot from comment #1) > Can it be RVO hitting? If it is it's misapplied - the example is reduced from a bug that frees memory too early.
Comment #3 by andrei — 2015-11-13T17:39:41Z
Looks like I wrongly used lst instead of lst2 in this example. Will get back soon.
Comment #4 by andrei — 2015-11-13T21:10:06Z
Forgot an incRef in popFront. The bug is invalid - sorry for the distraction!