From b797260e764d5244d05063fd661141f9337be82c Mon Sep 17 00:00:00 2001 From: RazvanN7 Date: Wed, 17 Jun 2020 16:43:39 +0800 Subject: [PATCH] Fix dup and idup property in the presence of copy constructors --- src/object.d | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/src/object.d b/src/object.d index 97b1276972..a13f0f9522 100644 --- a/src/object.d +++ b/src/object.d @@ -3105,11 +3105,20 @@ private U[] _dup(T, U)(T[] a) // pure nothrow depends on postblit import core.stdc.string : memcpy; void[] arr = _d_newarrayU(typeid(T[]), a.length); - memcpy(arr.ptr, cast(const(void)*)a.ptr, T.sizeof * a.length); + static if (__traits(hasCopyConstructor, T)) + { + _doCopyCtor(a, *cast(U[]*)&arr); + } + else + { + memcpy(arr.ptr, cast(const(void)*)a.ptr, T.sizeof * a.length); + } + auto res = *cast(U[]*)&arr; static if (__traits(hasPostblit, T)) _doPostblit(res); + return res; } @@ -3340,6 +3349,14 @@ private void _doPostblit(T)(T[] arr) } } +private void _doCopyCtor(T, U)(T[] src, U[] dst) +{ + foreach (i, ref elem; src) + { + dst[i].__ctor(elem); + } +} + @safe unittest { static struct S1 { int* p; } @@ -3421,6 +3438,59 @@ private void _doPostblit(T)(T[] arr) static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; })); } +@safe unittest +{ + static struct ArrElem + { + int a; + this(int a) + { + this.a = a; + } + this(ref const ArrElem) + { + a = 2; + } + this(ref ArrElem) immutable + { + a = 3; + } + } + + auto arr = [ArrElem(1), ArrElem(1)]; + + ArrElem[] b = arr.dup; + assert(b[0].a == 2 && b[1].a == 2); + + immutable ArrElem[] c = arr.idup; + assert(c[0].a == 3 && c[1].a == 3); +} + +@system unittest +{ + static struct Sunpure { this(ref const typeof(this)) @safe nothrow {} } + static struct Sthrow { this(ref const typeof(this)) @safe pure {} } + static struct Sunsafe { this(ref const typeof(this)) @system pure nothrow {} } + static assert( __traits(compiles, () { [].dup!Sunpure; })); + static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); + static assert( __traits(compiles, () { [].dup!Sthrow; })); + static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); + static assert( __traits(compiles, () { [].dup!Sunsafe; })); + static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); + + // for idup to work on structs that have copy constructors, it is necessary + // that the struct defines a copy constructor that creates immutable objects + static struct ISunpure { this(ref const typeof(this)) immutable @safe nothrow {} } + static struct ISthrow { this(ref const typeof(this)) immutable @safe pure {} } + static struct ISunsafe { this(ref const typeof(this)) immutable @system pure nothrow {} } + static assert( __traits(compiles, () { [].idup!ISunpure; })); + static assert(!__traits(compiles, () pure { [].idup!ISunpure; })); + static assert( __traits(compiles, () { [].idup!ISthrow; })); + static assert(!__traits(compiles, () nothrow { [].idup!ISthrow; })); + static assert( __traits(compiles, () { [].idup!ISunsafe; })); + static assert(!__traits(compiles, () @safe { [].idup!ISunsafe; })); +} + @safe unittest { static int*[] pureFoo() pure { return null; }