Implement Phobos side of DIP1014

This commit is contained in:
Les De Ridder 2019-06-10 21:07:29 +02:00
parent 6010a7ccde
commit 4be9b5f59f
2 changed files with 68 additions and 3 deletions

View file

@ -1046,8 +1046,8 @@ to its `.init` value after it is moved into target, otherwise it is
left unchanged.
Preconditions:
If source has internal pointers that point to itself, it cannot be moved, and
will trigger an assertion failure.
If source has internal pointers that point to itself and doesn't define
opPostMove, it cannot be moved, and will trigger an assertion failure.
Params:
source = Data to copy.
@ -1198,6 +1198,24 @@ pure nothrow @safe @nogc unittest
assert(s2.a == 2);
}
/// `opPostMove` will be called if defined:
pure nothrow @safe @nogc unittest
{
struct S
{
int a;
void opPostMove(const ref S old)
{
assert(a == old.a);
a++;
}
}
S s1;
s1.a = 41;
S s2 = move(s1);
assert(s2.a == 42);
}
private void trustedMoveImpl(T)(ref T source, ref T target) @trusted
{
moveImpl(source, target);
@ -1379,12 +1397,14 @@ void moveEmplace(T)(ref T source, ref T target) @system
import core.stdc.string : memcpy, memset;
import std.traits : hasAliasing, hasElaborateAssign,
hasElaborateCopyConstructor, hasElaborateDestructor,
hasElaborateMove,
isAssignable, isStaticArray;
static if (!is(T == class) && hasAliasing!T) if (!__ctfe)
{
import std.exception : doesPointTo;
assert(!doesPointTo(source, source), "Cannot move object with internal pointer.");
assert(!(doesPointTo(source, source) && !hasElaborateMove!T),
"Cannot move object with internal pointer unless `opPostMove` is defined.");
}
static if (is(T == struct))
@ -1396,6 +1416,9 @@ void moveEmplace(T)(ref T source, ref T target) @system
else
target = source;
static if (hasElaborateMove!T)
__move_post_blt(target, source);
// If the source defines a destructor or a postblit hook, we must obliterate the
// object in order to avoid double freeing and undue aliasing
static if (hasElaborateDestructor!T || hasElaborateCopyConstructor!T)

View file

@ -42,6 +42,7 @@
* $(LREF hasElaborateAssign)
* $(LREF hasElaborateCopyConstructor)
* $(LREF hasElaborateDestructor)
* $(LREF hasElaborateMove)
* $(LREF hasIndirections)
* $(LREF hasMember)
* $(LREF hasStaticMember)
@ -3791,6 +3792,47 @@ template hasElaborateDestructor(S)
static assert( hasElaborateDestructor!S7);
}
/**
True if `S` or any type embedded directly in the representation of `S`
defines elaborate move semantics. Elaborate move semantics are
introduced by defining `opPostMove(ref typeof(this))` for a `struct`.
Classes and unions never have elaborate move semantics.
*/
template hasElaborateMove(S)
{
import core.internal.traits : hasElabMove = hasElaborateMove;
alias hasElaborateMove = hasElabMove!(S);
}
///
@safe unittest
{
static assert(!hasElaborateMove!int);
static struct S1 { }
static struct S2 { void opPostMove(ref S2) {} }
static struct S3 { void opPostMove(inout ref S3) inout {} }
static struct S4 { void opPostMove(const ref S4) {} }
static struct S5 { void opPostMove(S5) {} }
static struct S6 { void opPostMove(int) {} }
static struct S7 { S3[1] field; }
static struct S8 { S3[] field; }
static struct S9 { S3[0] field; }
static struct S10 { @disable this(); S3 field; }
static assert(!hasElaborateMove!S1);
static assert( hasElaborateMove!S2);
static assert( hasElaborateMove!S3);
static assert( hasElaborateMove!(immutable S3));
static assert( hasElaborateMove!S4);
static assert(!hasElaborateMove!S5);
static assert(!hasElaborateMove!S6);
static assert( hasElaborateMove!S7);
static assert(!hasElaborateMove!S8);
static assert(!hasElaborateMove!S9);
static assert( hasElaborateMove!S10);
}
package alias Identity(alias A) = A;
/**