Skip to content

Commit 098e52e

Browse files
authored
Merge pull request #4682 from wilzbach/allocator_safe_5
Add attributes to makeArray - part 2 (length + init)
2 parents accf8d5 + b0e5a1b commit 098e52e

File tree

1 file changed

+71
-6
lines changed

1 file changed

+71
-6
lines changed

std/experimental/allocator/package.d

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -666,18 +666,34 @@ unittest
666666
assert(c.equal([0, 0, 0, 0, 0]));
667667
}
668668

669+
private enum hasPurePostblit(T) = !hasElaborateCopyConstructor!T ||
670+
is(typeof(() pure { T.init.__xpostblit(); }));
671+
672+
private enum hasPureDtor(T) = !hasElaborateDestructor!T ||
673+
is(typeof(() pure { T.init.__xdtor(); }));
674+
675+
// `true` when postblit and destructor of T cannot escape references to itself
676+
private enum canSafelyDeallocPostRewind(T) = hasPurePostblit!T && hasPureDtor!T;
677+
669678
/// Ditto
670679
T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length,
671680
auto ref T init)
672681
{
673682
if (!length) return null;
674683
auto m = alloc.allocate(T.sizeof * length);
675684
if (!m.ptr) return null;
676-
auto result = cast(T[]) m;
685+
auto result = () @trusted { return cast(T[]) m; } ();
677686
import std.traits : hasElaborateCopyConstructor;
678687
static if (hasElaborateCopyConstructor!T)
679688
{
680-
scope(failure) alloc.deallocate(m);
689+
scope(failure)
690+
{
691+
static if (canSafelyDeallocPostRewind!T)
692+
() @trusted { alloc.deallocate(m); } ();
693+
else
694+
alloc.deallocate(m);
695+
}
696+
681697
size_t i = 0;
682698
static if (hasElaborateDestructor!T)
683699
{
@@ -689,15 +705,16 @@ T[] makeArray(T, Allocator)(auto ref Allocator alloc, size_t length,
689705
}
690706
}
691707
}
708+
import std.conv : emplace;
692709
for (; i < length; ++i)
693710
{
694-
emplace!T(result.ptr + i, init);
711+
emplace!T(&result[i], init);
695712
}
696713
}
697714
else
698715
{
699716
alias U = Unqual!T;
700-
fillWithMemcpy(cast(U[]) result, *(cast(U*) &init));
717+
() @trusted { fillWithMemcpy(cast(U[]) result, *(cast(U*) &init)); }();
701718
}
702719
return result;
703720
}
@@ -722,7 +739,7 @@ unittest
722739
test!(immutable int)();
723740
}
724741

725-
unittest
742+
@system unittest
726743
{
727744
void test(A)(auto ref A alloc)
728745
{
@@ -733,10 +750,58 @@ unittest
733750
assert(a == [ 42, 42, 42, 42, 42 ]);
734751
}
735752
import std.experimental.allocator.gc_allocator : GCAllocator;
736-
test(GCAllocator.instance);
753+
(alloc) /*pure nothrow*/ @safe { test(alloc); } (GCAllocator.instance);
737754
test(theAllocator);
738755
}
739756

757+
// test failure with a pure, failing struct
758+
@safe unittest
759+
{
760+
import std.exception : assertThrown, enforce;
761+
762+
struct NoCopy
763+
{
764+
@disable this();
765+
766+
this(int b){}
767+
768+
// can't be copied
769+
this(this)
770+
{
771+
enforce(1 == 2);
772+
}
773+
}
774+
import std.experimental.allocator.mallocator : Mallocator;
775+
assertThrown(makeArray!NoCopy(Mallocator.instance, 10, NoCopy(42)));
776+
}
777+
778+
// test failure with an impure, failing struct
779+
@system unittest
780+
{
781+
import std.exception : assertThrown, enforce;
782+
783+
static int i = 0;
784+
struct Singleton
785+
{
786+
@disable this();
787+
788+
this(int b){}
789+
790+
// can't be copied
791+
this(this)
792+
{
793+
enforce(i++ == 0);
794+
}
795+
796+
~this()
797+
{
798+
i--;
799+
}
800+
}
801+
import std.experimental.allocator.mallocator : Mallocator;
802+
assertThrown(makeArray!Singleton(Mallocator.instance, 10, Singleton(42)));
803+
}
804+
740805
/// Ditto
741806
Unqual!(ElementEncodingType!R)[] makeArray(Allocator, R)(auto ref Allocator alloc, R range)
742807
if (isInputRange!R && !isInfinite!R)

0 commit comments

Comments
 (0)