From 7ab654df31174e18336c19eca64d3d3dec440e0c Mon Sep 17 00:00:00 2001 From: Les De Ridder Date: Mon, 10 Jun 2019 20:48:18 +0200 Subject: [PATCH 1/2] Implement druntime side of DIP1014 --- src/core/internal/traits.d | 19 ++++++++++++ src/object.d | 62 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/src/core/internal/traits.d b/src/core/internal/traits.d index 903f56b90b..c61ae74f43 100644 --- a/src/core/internal/traits.d +++ b/src/core/internal/traits.d @@ -294,6 +294,25 @@ template Fields(T) alias Fields = TypeTuple!T; } +// std.traits.hasElaborateMove +template hasElaborateMove(S) +{ + static if (__traits(isStaticArray, S) && S.length) + { + enum bool hasElaborateMove = hasElaborateMove!(typeof(S.init[0])); + } + else static if (is(S == struct)) + { + enum hasElaborateMove = (is(typeof(S.init.opPostMove(lvalueOf!S))) && + !is(typeof(S.init.opPostMove(rvalueOf!S)))) || + anySatisfy!(.hasElaborateMove, Fields!S); + } + else + { + enum bool hasElaborateMove = false; + } +} + // std.traits.hasElaborateDestructor template hasElaborateDestructor(S) { diff --git a/src/object.d b/src/object.d index 76a0b11c2f..96b1b4944c 100644 --- a/src/object.d +++ b/src/object.d @@ -127,6 +127,68 @@ if (is(Obj : Object)) assert(a < "я"); } +void __move_post_blt(S)(ref S newLocation, ref S oldLocation) nothrow + if (is(S == struct)) +{ + static foreach (memberName; __traits(allMembers, S)) + { + static if (is(typeof(__traits(getMember, S, memberName)) == struct)) + { + __move_post_blt(__traits(getMember, newLocation, memberName), __traits(getMember, oldLocation, memberName)); + } + } + + static if (__traits(hasMember, S, "opPostMove")) + { + import core.internal.traits : lvalueOf, rvalueOf; + static assert( is(typeof(S.init.opPostMove(lvalueOf!S))) && + !is(typeof(S.init.opPostMove(rvalueOf!S))), + "`" ~ S.stringof ~ ".opPostMove` must take exactly one argument of type `" ~ S.stringof ~ "` by reference"); + + newLocation.opPostMove(oldLocation); + } +} + +@safe nothrow unittest +{ + struct A + { + bool movedInto; + void opPostMove(const ref A oldLocation) + { + movedInto = true; + } + } + A src, dest; + __move_post_blt(dest, src); + assert(dest.movedInto); +} + +@safe nothrow unittest +{ + struct A + { + bool movedInto; + void opPostMove(const ref A oldLocation) + { + movedInto = true; + } + } + struct B + { + A a; + + bool movedInto; + void opPostMove(const ref B oldLocation) + { + movedInto = true; + } + } + B src, dest; + __move_post_blt(dest, src); + assert(dest.movedInto && dest.a.movedInto); +} + /** Destroys the given object and optionally resets to initial state. It's used to _destroy an object, calling its destructor or finalizer so it no longer From 963b2ff6f4e7115b5f2dd33d06abddb5b964c646 Mon Sep 17 00:00:00 2001 From: Les De Ridder Date: Fri, 28 Jun 2019 03:34:40 +0200 Subject: [PATCH 2/2] Add DIP1014 ddoc --- src/core/internal/traits.d | 2 +- src/object.d | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/core/internal/traits.d b/src/core/internal/traits.d index c61ae74f43..8b7cd71d88 100644 --- a/src/core/internal/traits.d +++ b/src/core/internal/traits.d @@ -294,7 +294,7 @@ template Fields(T) alias Fields = TypeTuple!T; } -// std.traits.hasElaborateMove +/// See $(REF hasElaborateMove, std,traits) template hasElaborateMove(S) { static if (__traits(isStaticArray, S) && S.length) diff --git a/src/object.d b/src/object.d index 96b1b4944c..769a9b1443 100644 --- a/src/object.d +++ b/src/object.d @@ -127,6 +127,23 @@ if (is(Obj : Object)) assert(a < "я"); } +/** + * Recursively calls the `opPostMove` callbacks of a struct and its members if + * they're defined. + * + * When moving a struct instance, the compiler emits a call to this function + * after blitting the instance and before releasing the original instance's + * memory. + * + * Params: + * newLocation = reference to struct instance being moved into + * oldLocation = reference to the original instance + * + * Note: + * This function is tentatively defined as `nothrow` to prevent + * `opPostMove` from being defined without `nothrow`, which would allow + * for possibly confusing changes in program flow. + */ void __move_post_blt(S)(ref S newLocation, ref S oldLocation) nothrow if (is(S == struct)) {