@@ -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
670679T[] 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
741806Unqual! (ElementEncodingType! R)[] makeArray (Allocator, R)(auto ref Allocator alloc, R range)
742807if (isInputRange! R && ! isInfinite! R)
0 commit comments