3 import core
.internal
.attributes
: betterC
;
7 Given a pointer `chunk` to uninitialized memory (but already typed
8 as `T`), constructs an object of non-`class` type `T` at that
9 address. If `T` is a class, initializes the class reference to null.
10 Returns: A pointer to the newly constructed object (which is the same
13 T
* emplace(T
)(T
* chunk
) @safe pure nothrow
15 import core
.internal
.lifetime
: emplaceRef
;
31 assert(s2
[0].i
== 42 && s2
[1].i
== 42);
50 Given a pointer `chunk` to uninitialized memory (but already typed
51 as a non-class type `T`), constructs an object of type `T` at
52 that address from arguments `args`. If `T` is a class, initializes
53 the class reference to `args[0]`.
54 This function can be `@trusted` if the corresponding constructor of
56 Returns: A pointer to the newly constructed object (which is the same
59 T
* emplace(T
, Args
...)(T
* chunk
, auto ref Args args
)
60 if (is(T
== struct) || Args
.length
== 1)
62 import core
.internal
.lifetime
: emplaceRef
;
64 emplaceRef
!T(*chunk
, forward
!args
);
74 assert(*emplace
!int(&a
, b
) == 42);
86 Given a raw memory area `chunk` (but already typed as a class type `T`),
87 constructs an object of `class` type `T` at that address. The constructor
88 is passed the arguments `Args`.
89 If `T` is an inner class whose `outer` field can be used to access an instance
90 of the enclosing class, then `Args` must not be empty, and the first member of it
91 must be a valid initializer for that `outer` field. Correct initialization of
92 this field is essential to access members of the outer class inside `T` methods.
94 This function is `@safe` if the corresponding constructor of `T` is `@safe`.
95 Returns: The newly constructed object.
97 T
emplace(T
, Args
...)(T chunk
, auto ref Args args
)
100 import core
.internal
.traits
: isInnerClass
;
102 static assert(!__traits(isAbstractClass
, T
), T
.stringof
~
103 " is abstract and it can't be emplaced");
105 // Initialize the object in its pre-ctor state
106 const initializer
= __traits(initSymbol
, T
);
107 () @trusted { (cast(void*) chunk
)[0 .. initializer
.length
] = cast(void[]) initializer
[]; }();
109 static if (isInnerClass
!T
)
111 static assert(Args
.length
> 0,
112 "Initializing an inner class requires a pointer to the outer class");
113 static assert(is(Args
[0] : typeof(T
.outer
)),
114 "The first argument must be a pointer to the outer class");
116 chunk
.outer
= args
[0];
117 alias args1
= args
[1..$];
119 else alias args1
= args
;
121 // Call the ctor if any
122 static if (is(typeof(chunk
.__ctor(forward
!args1
))))
124 // T defines a genuine constructor accepting args
125 // Go the classic route: write .init first, then call ctor
126 chunk
.__ctor(forward
!args1
);
130 static assert(args1
.length
== 0 && !is(typeof(&T
.__ctor
)),
131 "Don't know how to initialize an object of type "
132 ~ T
.stringof
~ " with arguments " ~ typeof(args1
).stringof
);
144 @safe this(int x
) { this.x
= x
; }
147 auto buf
= new void[__traits(classInstanceSize
, SafeClass
)];
148 auto support
= (() @trusted => cast(SafeClass
)(buf
.ptr
))();
149 auto safeClass
= emplace
!SafeClass(support
, 5);
150 assert(safeClass
.x
== 5);
155 @system this(int x
) { this.x
= x
; }
158 auto buf2
= new void[__traits(classInstanceSize
, UnsafeClass
)];
159 auto support2
= (() @trusted => cast(UnsafeClass
)(buf2
.ptr
))();
160 static assert(!__traits(compiles
, emplace
!UnsafeClass(support2
, 5)));
161 static assert(!__traits(compiles
, emplace
!UnsafeClass(buf2
, 5)));
172 @safe auto getI() { return i
; }
175 auto outerBuf
= new void[__traits(classInstanceSize
, Outer
)];
176 auto outerSupport
= (() @trusted => cast(Outer
)(outerBuf
.ptr
))();
178 auto innerBuf
= new void[__traits(classInstanceSize
, Outer
.Inner
)];
179 auto innerSupport
= (() @trusted => cast(Outer
.Inner
)(innerBuf
.ptr
))();
181 auto inner
= innerSupport
.emplace
!(Outer
.Inner
)(outerSupport
.emplace
!Outer
);
182 assert(inner
.getI
== 3);
186 Given a raw memory area `chunk`, constructs an object of `class` type `T` at
187 that address. The constructor is passed the arguments `Args`.
188 If `T` is an inner class whose `outer` field can be used to access an instance
189 of the enclosing class, then `Args` must not be empty, and the first member of it
190 must be a valid initializer for that `outer` field. Correct initialization of
191 this field is essential to access members of the outer class inside `T` methods.
193 `chunk` must be at least as large as `T` needs and should have an alignment
194 multiple of `T`'s alignment. (The size of a `class` instance is obtained by using
195 $(D __traits(classInstanceSize, T))).
197 This function can be `@trusted` if the corresponding constructor of `T` is `@safe`.
198 Returns: The newly constructed object.
200 T
emplace(T
, Args
...)(void[] chunk
, auto ref Args args
)
203 enum classSize
= __traits(classInstanceSize
, T
);
204 assert(chunk
.length
>= classSize
, "chunk size too small.");
206 enum alignment
= __traits(classInstanceAlignment
, T
);
207 assert((cast(size_t
) chunk
.ptr
) % alignment
== 0, "chunk is not aligned.");
209 return emplace
!T(cast(T
)(chunk
.ptr
), forward
!args
);
218 this(int i
){this.i
= i
;}
220 auto buf
= new void[__traits(classInstanceSize
, C
)];
221 auto c
= emplace
!C(buf
, 5);
227 @nogc pure nothrow @system unittest
229 // works with -betterC too:
231 static extern (C
++) class C
233 @nogc pure nothrow @safe:
240 int virtualGetI() { return i
; }
243 align(__traits(classInstanceAlignment
, C
)) byte[__traits(classInstanceSize
, C
)] buffer
;
244 C c
= emplace
!C(buffer
[], 42);
245 assert(c
.virtualGetI() == 42);
255 auto getI() { return i
; }
258 auto outerBuf
= new void[__traits(classInstanceSize
, Outer
)];
259 auto innerBuf
= new void[__traits(classInstanceSize
, Outer
.Inner
)];
260 auto inner
= innerBuf
.emplace
!(Outer
.Inner
)(outerBuf
.emplace
!Outer
);
261 assert(inner
.getI
== 3);
264 @nogc pure nothrow @safe unittest
266 static class __conv_EmplaceTestClass
268 @nogc @safe pure nothrow:
280 this(int i
, ref int j
)
282 assert(this.i
== 3 && i
== 5 && j
== 6);
289 align(__traits(classInstanceAlignment
, __conv_EmplaceTestClass
))
290 ubyte[__traits(classInstanceSize
, __conv_EmplaceTestClass
)] buf
;
291 auto support
= (() @trusted => cast(__conv_EmplaceTestClass
)(buf
.ptr
))();
293 auto fromRval
= emplace
!__conv_EmplaceTestClass(support
, 1);
294 assert(fromRval
.i
== 11);
296 auto fromLval
= emplace
!__conv_EmplaceTestClass(support
, var
);
297 assert(fromLval
.i
== 26);
299 auto k
= emplace
!__conv_EmplaceTestClass(support
, 5, var
);
305 Given a raw memory area `chunk`, constructs an object of non-$(D
306 class) type `T` at that address. The constructor is passed the
307 arguments `args`, if any.
309 `chunk` must be at least as large
310 as `T` needs and should have an alignment multiple of `T`'s
313 This function can be `@trusted` if the corresponding constructor of
315 Returns: A pointer to the newly constructed object.
317 T
* emplace(T
, Args
...)(void[] chunk
, auto ref Args args
)
320 import core
.internal
.traits
: Unqual
;
321 import core
.internal
.lifetime
: emplaceRef
;
323 assert(chunk
.length
>= T
.sizeof
, "chunk size too small.");
324 assert((cast(size_t
) chunk
.ptr
) % T
.alignof
== 0, "emplace: Chunk is not aligned.");
326 emplaceRef
!(T
, Unqual
!T
)(*cast(Unqual
!T
*) chunk
.ptr
, forward
!args
);
327 return cast(T
*) chunk
.ptr
;
338 void[S
.sizeof
] buf
= void;
342 auto s1
= emplace
!S(buf
, s
);
343 assert(s1
.a
== 42 && s1
.b
== 43);
346 // Bulk of emplace unittests starts here
349 @system unittest /* unions */
364 assert(u1
.a
== "hello");
367 @system unittest // https://issues.dlang.org/show_bug.cgi?id=15772
369 abstract class Foo
{}
372 // test in emplaceInitializer
373 static assert(!is(typeof(emplace
!Foo(cast(Foo
*) memory
.ptr
))));
374 static assert( is(typeof(emplace
!Bar(cast(Bar
*) memory
.ptr
))));
375 // test in the emplace overload that takes void[]
376 static assert(!is(typeof(emplace
!Foo(memory
))));
377 static assert( is(typeof(emplace
!Bar(memory
))));
383 struct S
{ @disable this(); }
385 static assert(!__traits(compiles
, emplace(&s
)));
423 static assert(!__traits(compiles
, emplace(&ss2
)));
426 static assert(!__traits(compiles
, emplace(&ss1
, s1
)));
442 assert(ss1
[0].i
== 5 && ss1
[1].i
== 5);
447 //Start testing emplace-args here
454 K k
= null, k2
= new K
;
470 void opAssign(S
){assert(0);}
475 assert(sa
[0].i
== 5 && sa
[1].i
== 5);
478 //Start testing emplace-struct here
480 // Test constructor branch
489 assert(x
== 5 && y
== 6);
495 void[S
.sizeof
] s1
= void;
497 assert(*emplace
!S(cast(S
*) s1
.ptr
, s2
) == s2
);
498 assert(*emplace
!S(cast(S
*) s1
, 44, 45) == S(44, 45));
503 static struct __conv_EmplaceTest
508 assert(this.i
== 3 && i
== 5);
511 this(int i
, ref int j
)
513 assert(i
== 5 && j
== 6);
524 __conv_EmplaceTest k
= void;
529 __conv_EmplaceTest x
= void;
535 auto z
= emplace
!__conv_EmplaceTest(new void[__conv_EmplaceTest
.sizeof
], 5, var
);
540 // Test matching fields branch
553 struct S
{ int a
, b
; this(int){} }
555 static assert(!__traits(compiles
, emplace
!S(&s
, 2, 3)));
561 struct S
{ int a
, b
= 7; }
562 S s1
= void, s2
= void;
565 assert(s1
.a
== 2 && s1
.b
== 7);
567 emplace
!S(&s2
, 2, 3);
568 assert(s2
.a
== 2 && s2
.b
== 3);
578 void opAssign(int){assert(0);}
579 void opAssign(S
){assert(0);}
590 //postblit precedence
594 //Works, but breaks in "-w -O" because of @@@9332@@@.
595 //Uncomment test when 9332 is fixed.
600 this(S other
){assert(false);}
601 this(int i
){this.i
= i
;}
605 assert(is(typeof({S b
= a
;}))); //Postblit
606 assert(is(typeof({S b
= S(a
);}))); //Constructor
616 static assert(!is(immutable S2
: S2
));
618 immutable is2
= (immutable S2
).init
;
622 //nested structs and postblit
628 this(int i
){p
= [i
].ptr
;}
638 void opAssign(const SS
)
646 assert(*ssa
.s
.p
== 5);
647 assert(ssa
.s
.p
!= ssb
.s
.p
);
662 static assert(!__traits(compiles
, emplace(&s1
, s1
))); // copy disabled
663 static assert(__traits(compiles
, emplace(&s1
, move(s1
)))); // move not affected
672 //static assert(!__traits(compiles, emplace(&s2, 1)));
673 emplace(&s2
, S2
.init
);
681 static assert(!__traits(compiles
, emplace(&ss1
, ss1
))); // copying disabled
682 static assert(__traits(compiles
, emplace(&ss1
, move(ss1
)))); // move unaffected
690 static assert(!__traits(compiles
, emplace(&ss2
, ss2
))); // copying disabled
691 static assert(__traits(compiles
, emplace(&ss2
, SS2
.init
))); // move is OK
694 // SS1 sss1 = s1; //This doesn't compile
695 // SS1 sss1 = SS1(s1); //This doesn't compile
696 // So emplace shouldn't compile either
697 static assert(!__traits(compiles
, emplace(&sss1
, s1
)));
698 static assert(!__traits(compiles
, emplace(&sss2
, s2
)));
705 //Castable immutability
711 static assert(is( immutable(S1
) : S1
));
713 auto sb
= immutable(S1
)(5);
717 //Un-castable immutability
723 static assert(!is(immutable(S2
) : S2
));
725 auto sb
= immutable(S2
)(null);
726 assert(!__traits(compiles
, emplace(&sa
, sb
)));
739 emplace(&s
, 1, null);
740 emplace(&s
, 2, &s
.i
);
741 assert(s
is S(2, &s
.i
));
790 SS1 ss
= SS1(1, S(2));
800 S
foo() @property{return s
;}
804 SS2 ss
= SS2(1, S(2));
810 version (CoreUnittest
)
813 private struct __std_conv_S
816 this(__std_conv_SS ss
) {assert(0);}
817 static opCall(__std_conv_SS ss
)
819 __std_conv_S s
; s
.i
= ss
.j
;
823 private struct __std_conv_SS
827 ref __std_conv_S
foo() return @property {s
.i
= j
; return s
;}
834 static assert(is(__std_conv_SS
: __std_conv_S
));
835 __std_conv_S s
= void;
836 __std_conv_SS ss
= __std_conv_SS(1);
838 __std_conv_S sTest1
= ss
; //this calls "SS alias this" (and not "S.this(SS)")
839 emplace(&s
, ss
); //"alias this" should take precedence in emplace over "opCall"
854 assert(s1
.a
is s2
.a
);
857 //safety & nothrow & CTFE
861 //emplace should be safe for anything with no elaborate opassign
869 this(int j
)@safe nothrow{i
= j
;}
880 void foo() @safe nothrow
886 emplace(ps1
, S1
.init
);
889 emplace(ps2
, S2
.init
);
895 T t
/+ = void+/; //CTFE void illegal
901 static assert(a
== 5);
903 static assert(b
.i
== 5);
905 static assert(c
.i
== 5);
920 int[2] get(){return [1, 2];}
936 assert(ss
.ii
== [1, 2]);
937 assert(iss
.ii
== [1, 2]);
946 @disable void opAssign(S
);
957 //Without constructor
962 static S1
opCall(int*){assert(0);}
965 static assert(!__traits(compiles
, emplace(&s
, 1)));
972 static S2
opCall(int*){assert(0);}
973 static S2
opCall(int){assert(0);}
974 this(int i
){this.i
= i
;}
980 //With postblit ambiguity
985 static S3
opCall(ref S3
){assert(0);}
988 emplace(&s
, S3
.init
);
1001 immutable int[2] ii
;
1012 static assert(!__traits(compiles
, {S ss
= S(uu
);}));
1013 static assert(!__traits(compiles
, emplace(&s
, uu
)));
1026 emplace(&sii
, sii2
);
1027 //emplace(&sii, uii2); //Sorry, this implementation doesn't know how to...
1028 //emplace(&uii, sii2); //Sorry, this implementation doesn't know how to...
1029 emplace(&uii
, uii2
);
1030 emplace(&sii
, sii2
[]);
1031 //emplace(&sii, uii2[]); //Sorry, this implementation doesn't know how to...
1032 //emplace(&uii, sii2[]); //Sorry, this implementation doesn't know how to...
1033 emplace(&uii
, uii2
[]);
1038 bool allowDestruction
= false;
1043 ~this(){assert(allowDestruction
);}
1051 emplace(&ss3
, ss2
[]);
1052 assert(ss1
[1] == s
);
1053 assert(ss2
[1] == s
);
1054 assert(ss3
[1] == s
);
1055 allowDestruction
= true;
1060 //Checks postblit, construction, and context pointer
1090 S
[2][2][2] sss
= void;
1094 @system unittest //Constness
1096 import core
.internal
.lifetime
: emplaceRef
;
1099 emplaceRef
!(const int)(a
, 5);
1102 const(int)* p
= void;
1103 emplaceRef
!(const int*)(p
, &i
);
1109 alias IS
= immutable(S
);
1111 emplaceRef
!IS(s
, IS());
1113 emplaceRef
!(IS
[2])(ss
, IS());
1115 IS
[2] iss
= IS
.init
;
1116 emplaceRef
!(IS
[2])(ss
, iss
);
1117 emplaceRef
!(IS
[2])(ss
, iss
[]);
1121 pure nothrow @safe @nogc unittest
1123 import core
.internal
.lifetime
: emplaceRef
;
1129 emplaceRef
!int(i
, 5);
1132 // Test attribute propagation for UDTs
1133 pure nothrow @safe /* @nogc */ unittest
1135 import core
.internal
.lifetime
: emplaceRef
;
1139 this(this) pure nothrow @safe @nogc {}
1143 emplaceRef(safe
, Safe());
1145 Safe
[1] safeArr
= [Safe()];
1146 Safe
[1] uninitializedSafeArr
= void;
1147 emplaceRef(uninitializedSafeArr
, safe
);
1148 emplaceRef(uninitializedSafeArr
, safeArr
);
1150 static struct Unsafe
1152 this(this) @system {}
1155 Unsafe unsafe
= void;
1156 static assert(!__traits(compiles
, emplaceRef(unsafe
, unsafe
)));
1158 Unsafe
[1] unsafeArr
= [Unsafe()];
1159 Unsafe
[1] uninitializedUnsafeArr
= void;
1160 static assert(!__traits(compiles
, emplaceRef(uninitializedUnsafeArr
, unsafe
)));
1161 static assert(!__traits(compiles
, emplaceRef(uninitializedUnsafeArr
, unsafeArr
)));
1175 import core
.stdc
.stdlib
: malloc
;
1176 void[] buf
= malloc(Node
.sizeof
)[0 .. Node
.sizeof
];
1178 const Node
* n
= emplace
!(const Node
)(buf
, 42, null, 10);
1179 assert(n
.payload
== 42);
1180 assert(n
.next
== null);
1181 assert(n
.refs
== 10);
1192 assert(x
== 5 && y
== 42);
1198 static align(__traits(classInstanceAlignment
, A
)) byte[__traits(classInstanceSize
, A
)] sbuf
;
1200 auto a
= emplace
!A(buf
, 55);
1201 assert(a
.x
== 55 && a
.y
== 55);
1203 // emplace in bigger buffer
1204 buf
= new byte[](__traits(classInstanceSize
, A
) + 10);
1205 a
= emplace
!A(buf
, 55);
1206 assert(a
.x
== 55 && a
.y
== 55);
1209 static assert(!is(typeof(emplace
!A(buf
))));
1212 //constructor arguments forwarding
1218 this()(auto ref long arg
)
1220 // assert that arg is an lvalue
1221 static assert(__traits(isRef
, arg
));
1223 this()(auto ref double arg
)
1224 // assert that arg is an rvalue
1226 static assert(!__traits(isRef
, arg
));
1231 emplace(&obj
, i
); // lvalue
1232 emplace(&obj
, 0.0); // rvalue
1234 // Bulk of emplace unittests ends here
1237 * Emplaces a copy of the specified source value into uninitialized memory,
1238 * i.e., simulates `T target = source` copy-construction for cases where the
1239 * target memory is already allocated and to be initialized with a copy.
1242 * source = value to be copied into target
1243 * target = uninitialized value to be initialized with a copy of source
1245 void copyEmplace(S
, T
)(ref S source
, ref T target
) @system
1246 if (is(immutable S
== immutable T
))
1248 import core
.internal
.traits
: BaseElemOf
, hasElaborateCopyConstructor
, Unconst
, Unqual
;
1250 // cannot have the following as simple template constraint due to nested-struct special case...
1251 static if (!__traits(compiles
, (ref S src
) { T tgt
= src
; }))
1253 alias B
= BaseElemOf
!T
;
1254 enum isNestedStruct
= is(B
== struct) && __traits(isNested
, B
);
1255 static assert(isNestedStruct
, "cannot copy-construct " ~ T
.stringof
~ " from " ~ S
.stringof
);
1260 import core
.stdc
.string
: memcpy
;
1261 memcpy(cast(Unqual
!(T
)*) &target
, cast(Unqual
!(T
)*) &source
, T
.sizeof
);
1264 static if (is(T
== struct))
1266 static if (__traits(hasPostblit
, T
))
1269 (cast() target
).__xpostblit();
1271 else static if (__traits(hasCopyConstructor
, T
))
1273 // https://issues.dlang.org/show_bug.cgi?id=22766
1274 import core
.internal
.lifetime
: emplaceInitializer
;
1275 emplaceInitializer(*(cast(Unqual
!T
*)&target
));
1276 static if (__traits(isNested
, T
))
1278 // copy context pointer
1279 *(cast(void**) &target
.tupleof
[$-1]) = cast(void*) source
.tupleof
[$-1];
1281 target
.__ctor(source
); // invoke copy ctor
1285 blit(); // no opAssign
1288 else static if (is(T
== E
[n
], E
, size_t n
))
1290 static if (hasElaborateCopyConstructor
!E
)
1295 for (i
= 0; i
< n
; i
++)
1296 copyEmplace(source
[i
], target
[i
]);
1300 // destroy, in reverse order, what we've constructed so far
1302 destroy(*cast(Unconst
!(E
)*) &target
[i
]);
1306 else // trivial copy
1308 blit(); // all elements at once
1313 *cast(Unconst
!(T
)*) &target
= *cast(Unconst
!(T
)*) &source
;
1319 @system pure nothrow @nogc unittest
1323 copyEmplace(source
, target
);
1324 assert(target
== 123);
1329 @system pure nothrow @nogc unittest
1331 immutable int[1][1] source
= [ [123] ];
1332 immutable int[1][1] target
= void;
1333 copyEmplace(source
, target
);
1334 assert(target
[0][0] == 123);
1339 @system pure nothrow @nogc unittest
1344 void opAssign(const scope ref S rhs
) @safe pure nothrow @nogc
1352 copyEmplace(source
, target
);
1353 assert(target
.x
== 42);
1356 // preserve shared-ness
1357 @system pure nothrow unittest
1359 auto s
= new Object();
1360 auto ss
= new shared Object();
1368 copyEmplace(ss
, st
);
1371 static assert(!__traits(compiles
, copyEmplace(s
, st
)));
1372 static assert(!__traits(compiles
, copyEmplace(ss
, t
)));
1375 // https://issues.dlang.org/show_bug.cgi?id=22766
1376 @system pure nothrow @nogc unittest
1381 this(int) @safe pure nothrow @nogc{}
1382 this(ref const(S
) other
) @safe pure nothrow @nogc {}
1387 copyEmplace(s1
, s2
);
1391 version (DigitalMars
) version (X86
) version (Posix
) version = DMD_X86_Posix
;
1393 // don't violate immutability for reference types
1394 @system pure nothrow unittest
1396 auto s
= new Object();
1397 auto si
= new immutable Object();
1400 immutable Object ti
;
1405 copyEmplace(si
, ti
);
1406 version (DMD_X86_Posix
) { /* wrongly fails without -O */ } else
1409 static assert(!__traits(compiles
, copyEmplace(s
, ti
)));
1410 static assert(!__traits(compiles
, copyEmplace(si
, t
)));
1413 version (CoreUnittest
)
1415 private void testCopyEmplace(S
, T
)(const scope T
* expected
= null)
1419 copyEmplace(source
, target
);
1421 assert(target
== *expected
);
1424 T expectedCopy
= source
;
1425 assert(target
== expectedCopy
);
1431 @system pure nothrow @nogc unittest
1435 @safe pure nothrow @nogc:
1437 this(this) { x
+= 10; }
1440 testCopyEmplace
!(S
, S
)();
1441 testCopyEmplace
!(immutable S
, S
)();
1442 testCopyEmplace
!(S
, immutable S
)();
1443 testCopyEmplace
!(immutable S
, immutable S
)();
1445 testCopyEmplace
!(S
[1], S
[1])();
1446 testCopyEmplace
!(immutable S
[1], S
[1])();
1448 // copying to an immutable static array works, but `T expected = source`
1449 // wrongly ignores the postblit: https://issues.dlang.org/show_bug.cgi?id=8950
1450 immutable S
[1] expectedImmutable
= [S(52)];
1451 testCopyEmplace
!(S
[1], immutable S
[1])(&expectedImmutable
);
1452 testCopyEmplace
!(immutable S
[1], immutable S
[1])(&expectedImmutable
);
1455 // copy constructors
1456 @system pure nothrow @nogc unittest
1460 @safe pure nothrow @nogc:
1462 this(int x
) { this.x
= x
; }
1463 this(const scope ref S rhs
) { x
= rhs
.x
+ 10; }
1464 this(const scope ref S rhs
) immutable { x
= rhs
.x
+ 20; }
1467 testCopyEmplace
!(S
, S
)();
1468 testCopyEmplace
!(immutable S
, S
)();
1469 testCopyEmplace
!(S
, immutable S
)();
1470 testCopyEmplace
!(immutable S
, immutable S
)();
1472 // static arrays work, but `T expected = source` wrongly ignores copy ctors
1473 // https://issues.dlang.org/show_bug.cgi?id=20365
1474 S
[1] expectedMutable
= [S(52)];
1475 immutable S
[1] expectedImmutable
= [immutable S(62)];
1476 testCopyEmplace
!(S
[1], S
[1])(&expectedMutable
);
1477 testCopyEmplace
!(immutable S
[1], S
[1])(&expectedMutable
);
1478 testCopyEmplace
!(S
[1], immutable S
[1])(&expectedImmutable
);
1479 testCopyEmplace
!(immutable S
[1], immutable S
[1])(&expectedImmutable
);
1482 // copy constructor in nested struct
1483 @system pure nothrow unittest
1488 @safe pure nothrow @nogc:
1490 this(size_t x
) { this.x
= x
; }
1491 this(const scope ref S rhs
)
1493 assert(x
== 42); // T.init
1502 immutable S target
= void;
1503 copyEmplace(source
, target
);
1504 assert(target
is source
);
1505 assert(copies
== 1);
1510 immutable S
[1] source
= [immutable S(456)];
1512 copyEmplace(source
, target
);
1513 assert(target
[0] is source
[0]);
1514 assert(copies
== 1);
1518 // destruction of partially copied static array
1523 __gshared
int[] deletions
;
1525 this(this) { if (x
== 5) throw new Exception(""); }
1526 ~this() { deletions
~= x
; }
1529 alias T
= immutable S
[3][2];
1530 T source
= [ [S(1), S(2), S(3)], [S(4), S(5), S(6)] ];
1534 copyEmplace(source
, target
);
1539 static immutable expectedDeletions
= [ 4, 3, 2, 1 ];
1540 version (DigitalMars
)
1542 assert(S
.deletions
== expectedDeletions ||
1543 S
.deletions
== [ 4 ]); // FIXME: happens with -O
1546 assert(S
.deletions
== expectedDeletions
);
1551 Forwards function arguments while keeping `out`, `ref`, and `lazy` on
1555 args = a parameter list or an $(REF AliasSeq,std,meta).
1557 An `AliasSeq` of `args` with `out`, `ref`, and `lazy` saved.
1559 template forward(args
...)
1561 import core
.internal
.traits
: AliasSeq
;
1563 template fwd(alias arg
)
1565 // by ref || lazy || const/immutable
1566 static if (__traits(isRef
, arg
) ||
1567 __traits(isOut
, arg
) ||
1568 __traits(isLazy
, arg
) ||
1569 !is(typeof(move(arg
))))
1573 @property auto fwd()
1575 version (DigitalMars
) { /* @@BUG 23890@@ */ } else pragma(inline
, true);
1580 alias Result
= AliasSeq
!();
1581 static foreach (arg
; args
)
1582 Result
= AliasSeq
!(Result
, fwd
!arg
);
1583 static if (Result
.length
== 1)
1584 alias forward
= Result
[0];
1586 alias forward
= Result
;
1594 static int foo(int n
) { return 1; }
1595 static int foo(ref int n
) { return 2; }
1599 int bar()(auto ref int x
) { return C
.foo(forward
!x
); }
1602 int baz()(auto ref int x
) { return C
.foo(x
); }
1605 assert(bar(1) == 1);
1606 assert(bar(i
) == 2);
1608 assert(baz(1) == 2);
1609 assert(baz(i
) == 2);
1615 void foo(int n
, ref string s
) { s
= null; foreach (i
; 0 .. n
) s
~= "Hello"; }
1617 // forwards all arguments which are bound to parameter tuple
1618 void bar(Args
...)(auto ref Args args
) { return foo(forward
!args
); }
1620 // forwards all arguments with swapping order
1621 void baz(Args
...)(auto ref Args args
) { return foo(forward
!args
[$/2..$], forward
!args
[0..$/2]); }
1625 assert(s
== "Hello");
1627 assert(s
== "HelloHello");
1632 auto foo(TL
...)(auto ref TL args
)
1635 foreach (i
, _
; args
)
1637 //pragma(msg, "[",i,"] ", __traits(isRef, args[i]) ? "L" : "R");
1638 result
~= __traits(isRef
, args
[i
]) ?
"L" : "R";
1643 string
bar(TL
...)(auto ref TL args
)
1645 return foo(forward
!args
);
1647 string
baz(TL
...)(auto ref TL args
)
1650 return foo(forward
!args
[3], forward
!args
[2], 1, forward
!args
[1], forward
!args
[0], x
);
1654 S
makeS(){ return S(); }
1657 assert(bar(S(), makeS(), n
, s
) == "RRLL");
1658 assert(baz(S(), makeS(), n
, s
) == "LLRRRL");
1664 ref int foo(return ref int a
) { return a
; }
1665 ref int bar(Args
)(auto ref Args args
)
1667 return foo(forward
!args
);
1669 static assert(!__traits(compiles
, { auto x1
= bar(3); })); // case of NG
1671 auto x2
= bar(value
); // case of OK
1689 this()(auto ref X x
)
1698 this()(auto ref X x
)
1702 this()(auto ref const X x
)
1710 auto constX
= (){ const X x
; return x
; };
1711 static assert(__traits(compiles
, { Y y
= x
; }));
1712 static assert(__traits(compiles
, { Y y
= X(); }));
1713 static assert(!__traits(compiles
, { Y y
= cx
; }));
1714 static assert(!__traits(compiles
, { Y y
= constX(); }));
1715 static assert(__traits(compiles
, { Z z
= x
; }));
1716 static assert(__traits(compiles
, { Z z
= X(); }));
1717 static assert(__traits(compiles
, { Z z
= cx
; }));
1718 static assert(__traits(compiles
, { Z z
= constX(); }));
1723 assert(y1
.x_
.i
== 1);
1726 assert(y2
.x_
.i
== 0);
1730 assert(z1
.x_
.i
== 1);
1733 assert(z2
.x_
.i
== 0);
1735 // ref const lvalue, copy
1736 assert(z3
.x_
.i
== 1);
1738 // const rvalue, copy
1739 assert(z4
.x_
.i
== 1);
1746 int foo1(lazy int i
) { return i
; }
1747 int foo2(A
)(auto ref A i
) { return foo1(forward
!i
); }
1748 int foo3(lazy int i
) { return foo2(i
); }
1751 assert(foo3({ ++numCalls
; return 42; }()) == 42);
1752 assert(numCalls
== 1);
1759 int foo1(int a
, int b
) { return a
+ b
; }
1760 int foo2(A
...)(auto ref A args
) { return foo1(forward
!args
); }
1761 int foo3(int a
, lazy int b
) { return foo2(a
, b
); }
1764 assert(foo3(11, { ++numCalls
; return 31; }()) == 42);
1765 assert(numCalls
== 1);
1772 int foo1(int a
, lazy int b
) { return a
+ b
; }
1773 int foo2(A
...)(auto ref A args
) { return foo1(forward
!args
); }
1774 int foo3(int a
, int b
) { return foo2(a
, b
); }
1776 assert(foo3(11, 31) == 42);
1783 void foo1(int a
, out int b
) { b
= a
; }
1784 void foo2(A
...)(auto ref A args
) { foo1(forward
!args
); }
1785 void foo3(int a
, out int b
) { foo2(a
, b
); }
1794 Moves `source` into `target`, via a destructive copy when necessary.
1796 If `T` is a struct with a destructor or postblit defined, source is reset
1797 to its `.init` value after it is moved into target, otherwise it is
1801 If source has internal pointers that point to itself and doesn't define
1802 opPostMove, it cannot be moved, and will trigger an assertion failure.
1805 source = Data to copy.
1806 target = Where to copy into. The destructor, if any, is invoked before the
1809 void move(T
)(ref T source
, ref T target
)
1811 moveImpl(target
, source
);
1814 /// For non-struct types, `move` just performs `target = source`:
1817 Object obj1
= new Object
;
1822 assert(obj3
is obj1
);
1824 assert(obj2
is obj1
);
1828 pure nothrow @safe @nogc unittest
1830 // Structs without destructors are simply copied
1836 S1 s11
= { 10, 11 };
1841 assert(s12
== S1(10, 11));
1844 // But structs with destructors or postblits are reset to their .init value
1845 // after copying to the target.
1851 ~this() pure nothrow @safe @nogc { }
1858 assert(s21
== S2(1, 2));
1859 assert(s22
== S2(3, 4));
1864 import core
.internal
.traits
;
1867 Object obj1
= new Object
;
1871 assert(obj3
is obj1
);
1873 static struct S1
{ int a
= 1, b
= 2; }
1874 S1 s11
= { 10, 11 };
1877 assert(s11
.a
== 10 && s11
.b
== 11 && s12
.a
== 10 && s12
.b
== 11);
1879 static struct S2
{ int a
= 1; int * b
; }
1880 S2 s21
= { 10, null };
1886 // Issue 5661 test(1)
1889 static struct X
{ int n
= 0; ~this(){n
= 0;} }
1892 static assert(hasElaborateDestructor
!S3
);
1896 assert(s31
.x
.n
== 0);
1897 assert(s32
.x
.n
== 1);
1899 // Issue 5661 test(2)
1902 static struct X
{ int n
= 0; this(this){n
= 0;} }
1905 static assert(hasElaborateCopyConstructor
!S4
);
1909 assert(s41
.x
.n
== 0);
1910 assert(s42
.x
.n
== 1);
1923 T
move(T
)(return scope ref T source
)
1925 return moveImpl(source
);
1928 /// Non-copyable structs can still be moved:
1929 pure nothrow @safe @nogc unittest
1934 @disable this(this);
1935 ~this() pure nothrow @safe @nogc {}
1944 // https://issues.dlang.org/show_bug.cgi?id=20869
1945 // `move` should propagate the attributes of `opPostMove`
1950 void opPostMove(const ref S old
) nothrow @system
1953 new int(i
++); // Force @gc impure @system
1957 alias T
= void function() @system nothrow;
1958 static assert(is(typeof({ S s
; move(s
); }) == T
));
1959 static assert(is(typeof({ S s
; move(s
, s
); }) == T
));
1962 private void moveImpl(T
)(scope ref T target
, return scope ref T source
)
1964 import core
.internal
.traits
: hasElaborateDestructor
;
1966 static if (is(T
== struct))
1968 // Unsafe when compiling without -preview=dip1000
1969 if ((() @trusted => &source
== &target
)()) return;
1970 // Destroy target before overwriting it
1971 static if (hasElaborateDestructor
!T
) target
.__xdtor();
1973 // move and emplace source into target
1974 moveEmplaceImpl(target
, source
);
1977 private T
moveImpl(T
)(return scope ref T source
)
1979 // Properly infer safety from moveEmplaceImpl as the implementation below
1980 // might void-initialize pointers in result and hence needs to be @trusted
1981 if (false) moveEmplaceImpl(source
, source
);
1983 return trustedMoveImpl(source
);
1986 private T
trustedMoveImpl(T
)(return scope ref T source
) @trusted
1989 moveEmplaceImpl(result
, source
);
1995 import core
.internal
.traits
;
1998 Object obj1
= new Object
;
2000 Object obj3
= move(obj2
);
2001 assert(obj3
is obj1
);
2003 static struct S1
{ int a
= 1, b
= 2; }
2004 S1 s11
= { 10, 11 };
2006 assert(s11
.a
== 10 && s11
.b
== 11 && s12
.a
== 10 && s12
.b
== 11);
2008 static struct S2
{ int a
= 1; int * b
; }
2009 S2 s21
= { 10, null };
2015 // Issue 5661 test(1)
2018 static struct X
{ int n
= 0; ~this(){n
= 0;} }
2021 static assert(hasElaborateDestructor
!S3
);
2025 assert(s31
.x
.n
== 0);
2026 assert(s32
.x
.n
== 1);
2028 // Issue 5661 test(2)
2031 static struct X
{ int n
= 0; this(this){n
= 0;} }
2034 static assert(hasElaborateCopyConstructor
!S4
);
2038 assert(s41
.x
.n
== 0);
2039 assert(s42
.x
.n
== 1);
2054 static struct S
{ int n
= 0; ~this() @system { n
= 0; } }
2056 static assert(!__traits(compiles
, () @safe { move(a
, b
); }));
2057 static assert(!__traits(compiles
, () @safe { move(a
); }));
2059 () @trusted { move(a
, b
); }();
2062 () @trusted { move(a
); }();
2065 /+ this can't be tested in druntime, tests are still run in phobos
2066 @safe unittest//Issue 6217
2068 import std.algorithm.iteration : map;
2069 auto x = map!"a"([1,2,3]);
2074 @safe unittest// Issue 8055
2094 @system unittest// Issue 8057
2102 // Access to enclosing scope
2108 // Move nested struct
2117 static struct Array(T
)
2119 // nested struct has no member
2125 Array
!int.Payload x
= void;
2130 private enum bool hasContextPointers(T
) = {
2131 static if (__traits(isStaticArray
, T
))
2133 return hasContextPointers
!(typeof(T
.init
[0]));
2135 else static if (is(T
== struct))
2137 import core
.internal
.traits
: anySatisfy
;
2138 return __traits(isNested
, T
) || anySatisfy
!(hasContextPointers
, typeof(T
.tupleof
));
2143 @safe @nogc nothrow pure unittest
2145 static assert(!hasContextPointers
!int);
2146 static assert(!hasContextPointers
!(void*));
2149 static assert(!hasContextPointers
!S
);
2150 static assert(!hasContextPointers
!(S
[1]));
2157 static assert(hasContextPointers
!Nested
);
2158 static assert(hasContextPointers
!(Nested
[1]));
2160 static struct OneLevel
2167 static assert(hasContextPointers
!OneLevel
);
2168 static assert(hasContextPointers
!(OneLevel
[1]));
2170 static struct TwoLevels
2177 static assert(hasContextPointers
!TwoLevels
);
2178 static assert(hasContextPointers
!(TwoLevels
[1]));
2185 // unions can have false positives, so this query ignores them
2186 static assert(!hasContextPointers
!U
);
2189 // target must be first-parameter, because in void-functions DMD + dip1000 allows it to take the place of a return-scope
2190 private void moveEmplaceImpl(T
)(scope ref T target
, return scope ref T source
)
2192 // TODO: this assert pulls in half of phobos. we need to work out an alternative assert strategy.
2193 // static if (!is(T == class) && hasAliasing!T) if (!__ctfe)
2195 // import std.exception : doesPointTo;
2196 // assert(!doesPointTo(source, source) && !hasElaborateMove!T),
2197 // "Cannot move object with internal pointer unless `opPostMove` is defined.");
2200 import core
.internal
.traits
: hasElaborateAssign
, isAssignable
, hasElaborateMove
,
2201 hasElaborateDestructor
, hasElaborateCopyConstructor
;
2202 static if (is(T
== struct))
2205 // Unsafe when compiling without -preview=dip1000
2206 assert((() @trusted => &source
!is &target
)(), "source and target must not be identical");
2208 static if (hasElaborateAssign
!T ||
!isAssignable
!T
)
2210 import core
.stdc
.string
: memcpy
;
2211 () @trusted { memcpy(&target
, &source
, T
.sizeof
); }();
2216 static if (hasElaborateMove
!T
)
2217 __move_post_blt(target
, source
);
2219 // If the source defines a destructor or a postblit hook, we must obliterate the
2220 // object in order to avoid double freeing and undue aliasing
2221 static if (hasElaborateDestructor
!T || hasElaborateCopyConstructor
!T
)
2223 // If there are members that are nested structs, we must take care
2224 // not to erase any context pointers, so we might have to recurse
2225 static if (__traits(isZeroInit
, T
))
2228 wipe(source
, ref () @trusted { return *cast(immutable(T
)*) __traits(initSymbol
, T
).ptr
; } ());
2231 else static if (__traits(isStaticArray
, T
))
2233 static if (T
.length
)
2235 static if (!hasElaborateMove
!T
&&
2236 !hasElaborateDestructor
!T
&&
2237 !hasElaborateCopyConstructor
!T
)
2239 // Single blit if no special per-instance handling is required
2242 assert(source
.ptr
!is target
.ptr
, "source and target must not be identical");
2243 *cast(ubyte[T
.sizeof
]*) &target
= *cast(ubyte[T
.sizeof
]*) &source
;
2248 for (size_t i
= 0; i
< source
.length
; ++i
)
2249 moveEmplaceImpl(target
[i
], source
[i
]);
2255 // Primitive data (including pointers and arrays) or class -
2256 // assignment works great
2262 * Similar to $(LREF move) but assumes `target` is uninitialized. This
2263 * is more efficient because `source` can be blitted over `target`
2264 * without destroying or initializing it first.
2267 * source = value to be moved into target
2268 * target = uninitialized value to be filled by source
2270 void moveEmplace(T
)(ref T source
, ref T target
) @system
2272 moveEmplaceImpl(target
, source
);
2277 pure nothrow @nogc @system unittest
2282 this(int* ptr
) { _ptr
= ptr
; }
2283 ~this() { if (_ptr
) ++*_ptr
; }
2288 Foo foo1
= void; // uninitialized
2289 auto foo2
= Foo(&val
); // initialized
2290 assert(foo2
._ptr
is &val
);
2292 // Using `move(foo2, foo1)` would have an undefined effect because it would destroy
2293 // the uninitialized foo1.
2294 // moveEmplace directly overwrites foo1 without destroying or initializing it first.
2295 moveEmplace(foo2
, foo1
);
2296 assert(foo1
._ptr
is &val
);
2297 assert(foo2
._ptr
is null);
2302 pure nothrow @nogc @system unittest
2307 this(int* ptr
) { _ptr
= ptr
; }
2308 ~this() { if (_ptr
) ++*_ptr
; }
2314 Foo
[1] foo1
= void; // uninitialized
2315 Foo
[1] foo2
= [Foo(&val
)];// initialized
2316 assert(foo2
[0]._ptr
is &val
);
2318 // Using `move(foo2, foo1)` would have an undefined effect because it would destroy
2319 // the uninitialized foo1.
2320 // moveEmplace directly overwrites foo1 without destroying or initializing it first.
2321 moveEmplace(foo2
, foo1
);
2322 assert(foo1
[0]._ptr
is &val
);
2323 assert(foo2
[0]._ptr
is null);
2329 // https://issues.dlang.org/show_bug.cgi?id=18913
2332 static struct NoCopy
2336 @disable this(this);
2339 static void f(NoCopy
[2]) { }
2341 NoCopy
[2] ncarray
= [ NoCopy(1), NoCopy(2) ];
2343 static assert(!__traits(compiles
, f(ncarray
)));
2351 import core
.stdc
.stdio
: printf
;
2354 /// Implementation of `_d_delstruct` and `_d_delstructTrace`
2355 template _d_delstructImpl(T
)
2357 private void _d_delstructImpure(ref T p
)
2359 debug(PRINTF
) printf("_d_delstruct(%p)\n", p
);
2361 import core
.memory
: GC
;
2369 * This is called for a delete statement where the value being deleted is a
2370 * pointer to a struct with a destructor but doesn't have an overloaded
2371 * `delete` operator.
2374 * p = pointer to the value to be deleted
2377 * This function template was ported from a much older runtime hook that
2378 * bypassed safety, purity, and throwabilty checks. To prevent breaking
2379 * existing code, this function template is temporarily declared
2380 * `@trusted` until the implementation can be brought up to modern D
2383 void _d_delstruct(ref T p
) @trusted @nogc pure nothrow
2387 alias Type
= void function(ref T P
) @nogc pure nothrow;
2388 (cast(Type
) &_d_delstructImpure
)(p
);
2392 version (D_ProfileGC
)
2394 import core
.internal
.array
.utils
: _d_HookTraceImpl
;
2396 private enum errorMessage
= "Cannot delete struct if compiling without support for runtime type information!";
2399 * TraceGC wrapper around $(REF _d_delstruct, core,lifetime,_d_delstructImpl).
2402 * This function template was ported from a much older runtime hook that
2403 * bypassed safety, purity, and throwabilty checks. To prevent breaking
2404 * existing code, this function template is temporarily declared
2405 * `@trusted` until the implementation can be brought up to modern D
2408 alias _d_delstructTrace
= _d_HookTraceImpl
!(T
, _d_delstruct
, errorMessage
);
2412 @system pure nothrow unittest
2415 struct S
{ ~this() nothrow { ++dtors
; } }
2418 _d_delstructImpl
!(typeof(s
))._d_delstruct(s
);
2424 @system pure unittest
2429 struct Inner
{ ~this() { ++innerDtors
; } }
2445 _d_delstructImpl
!(typeof(i1
))._d_delstruct(i1
);
2448 _d_delstructImpl
!(typeof(i2
))._d_delstruct(i2
);
2453 Outer
*o
= new Outer(0);
2454 _d_delstructImpl
!(typeof(o
))._d_delstruct(o
);
2457 assert(innerDtors
== 2);
2458 assert(outerDtors
== 1);
2461 // https://issues.dlang.org/show_bug.cgi?id=25552
2462 pure nothrow @system unittest
2468 char[1] arr
; // char.init is not 0
2473 Nested
[1] dst
= void;
2474 Nested
[1] src
= [Nested(['a'])];
2476 moveEmplace(src
, dst
);
2478 assert(dst
[0].arr
== ['a']);
2479 assert(src
[0].arr
== [char.init
]);
2480 assert(dst
[0].tupleof
[$-1] is src
[0].tupleof
[$-1]);
2485 // https://issues.dlang.org/show_bug.cgi?id=25552
2494 static struct NotNested
2504 static struct Deeper
2509 static assert(__traits(isZeroInit
, Nested
));
2510 static assert(__traits(isZeroInit
, NotNested
));
2511 static assert(__traits(isZeroInit
, Deep
));
2512 static assert(__traits(isZeroInit
, Deeper
));
2515 auto a
= NotNested(Nested());
2516 assert(a
.n
.tupleof
[$-1]);
2518 assert(b
.n
.tupleof
[$-1]);
2519 assert(a
.n
.tupleof
[$-1] is b
.n
.tupleof
[$-1]);
2521 auto c
= Deep(NotNested(Nested()));
2523 assert(d
.nn
.n
.tupleof
[$-1]);
2524 assert(c
.nn
.n
.tupleof
[$-1] is d
.nn
.n
.tupleof
[$-1]);
2526 auto e
= Deeper([NotNested(Nested())]);
2528 assert(f
.nn
[0].n
.tupleof
[$-1]);
2529 assert(e
.nn
[0].n
.tupleof
[$-1] is f
.nn
[0].n
.tupleof
[$-1]);
2534 // https://issues.dlang.org/show_bug.cgi?id=25552
2540 align(32) // better still find context pointer correctly!
2541 int[3] stuff
= [0, 1, 2];
2545 static struct NoAssign
2548 @disable void opAssign(typeof(this));
2551 static struct NotNested
2554 align(Nested
.alignof
* 4) // better still find context pointer correctly!
2556 auto after
= NoAssign(43);
2564 static struct Deeper
2569 static assert(!__traits(isZeroInit
, Nested
));
2570 static assert(!__traits(isZeroInit
, NotNested
));
2571 static assert(!__traits(isZeroInit
, Deep
));
2572 static assert(!__traits(isZeroInit
, Deeper
));
2575 auto a
= NotNested(1, Nested([3, 4, 5]), NoAssign(2));
2577 assert(b
.n
.tupleof
[$-1]);
2578 assert(a
.n
.tupleof
[$-1] is b
.n
.tupleof
[$-1]);
2579 assert(a
.n
.stuff
== [0, 1, 2]);
2580 assert(a
.before
== 42);
2581 assert(a
.after
== NoAssign(43));
2583 auto c
= Deep(NotNested(1, Nested([3, 4, 5]), NoAssign(2)));
2585 assert(d
.nn
.n
.tupleof
[$-1]);
2586 assert(c
.nn
.n
.tupleof
[$-1] is d
.nn
.n
.tupleof
[$-1]);
2587 assert(c
.nn
.n
.stuff
== [0, 1, 2]);
2588 assert(c
.nn
.before
== 42);
2589 assert(c
.nn
.after
== NoAssign(43));
2591 auto e
= Deeper([NotNested(1, Nested([3, 4, 5]), NoAssign(2))]);
2593 assert(f
.nn
[0].n
.tupleof
[$-1]);
2594 assert(e
.nn
[0].n
.tupleof
[$-1] is f
.nn
[0].n
.tupleof
[$-1]);
2595 assert(e
.nn
[0].n
.stuff
== [0, 1, 2]);
2596 assert(e
.nn
[0].before
== 42);
2597 assert(e
.nn
[0].after
== NoAssign(43));
2602 // wipes source after moving
2603 pragma(inline
, true)
2604 private void wipe(T
, Init
...)(return scope ref T source
, ref const scope Init initializer
) @trusted
2606 ((Init
.length
== 1) && (is(immutable T
== immutable Init
[0]))))
2608 static if (__traits(isStaticArray
, T
) && hasContextPointers
!T
)
2610 for (auto i
= 0; i
< T
.length
; i
++)
2611 static if (Init
.length
)
2612 wipe(source
[i
], initializer
[0][i
]);
2616 else static if (is(T
== struct) && hasContextPointers
!T
)
2618 import core
.internal
.traits
: anySatisfy
;
2619 static if (anySatisfy
!(hasContextPointers
, typeof(T
.tupleof
)))
2621 static foreach (i
; 0 .. T
.tupleof
.length
- __traits(isNested
, T
))
2622 static if (Init
.length
)
2623 wipe(source
.tupleof
[i
], initializer
[0].tupleof
[i
]);
2625 wipe(source
.tupleof
[i
]);
2629 static if (__traits(isNested
, T
))
2630 enum sz
= T
.tupleof
[$-1].offsetof
;
2634 static if (Init
.length
)
2635 *cast(ubyte[sz
]*) &source
= *cast(ubyte[sz
]*) &initializer
[0];
2637 *cast(ubyte[sz
]*) &source
= 0;
2642 import core
.internal
.traits
: hasElaborateAssign
, isAssignable
;
2643 static if (Init
.length
)
2645 static if (hasElaborateAssign
!T ||
!isAssignable
!T
)
2646 *cast(ubyte[T
.sizeof
]*) &source
= *cast(ubyte[T
.sizeof
]*) &initializer
[0];
2648 source
= *cast(T
*) &initializer
[0];
2652 *cast(ubyte[T
.sizeof
]*) &source
= 0;
2658 * Allocate an exception of type `T` from the exception pool.
2659 * `T` must be `Throwable` or derived from it and cannot be a COM or C++ class.
2662 * This function does not call the constructor of `T` because that would require
2663 * `forward!args`, which causes errors with -dip1008. This inconvenience will be
2664 * removed once -dip1008 works as intended.
2667 * allocated instance of type `T`
2669 T
_d_newThrowable(T
)() @trusted
2670 if (is(T
: Throwable
) && __traits(getLinkage
, T
) == "D")
2672 debug(PRINTF
) printf("_d_newThrowable(%s)\n", cast(char*) T
.stringof
);
2674 import core
.memory
: pureMalloc
;
2675 auto init
= __traits(initSymbol
, T
);
2676 void* p
= pureMalloc(init
.length
);
2679 import core
.exception
: onOutOfMemoryError
;
2680 onOutOfMemoryError();
2683 debug(PRINTF
) printf(" p = %p\n", p
);
2686 p
[0 .. init
.length
] = cast(void[]) init
[];
2688 import core
.internal
.traits
: hasIndirections
;
2689 if (hasIndirections
!T
)
2691 // Inform the GC about the pointers in the object instance
2692 import core
.memory
: GC
;
2693 GC
.addRange(p
, init
.length
);
2696 debug(PRINTF
) printf("initialization done\n");
2698 (cast(Throwable
) p
).refcount() = 1;
2707 this(string msg
= "", Throwable nextInChain
= null)
2709 super(msg
, nextInChain
);
2713 Throwable exc
= _d_newThrowable
!Exception();
2714 Throwable e
= _d_newThrowable
!E();
2716 assert(exc
.refcount() == 1);
2717 assert(e
.refcount() == 1);
2721 * Create a new class instance.
2722 * Allocates memory and sets fields to their initial value, but does not call a
2725 * new C() // _d_newclass!(C)()
2727 * Returns: newly created object
2729 T
_d_newclassT(T
)() @trusted
2732 import core
.internal
.traits
: hasIndirections
;
2733 import core
.exception
: onOutOfMemoryError
;
2734 import core
.memory
: pureMalloc
;
2735 import core
.memory
: GC
;
2737 alias BlkAttr
= GC
.BlkAttr
;
2739 auto init
= __traits(initSymbol
, T
);
2742 static if (__traits(isCOMClass
, T
))
2744 // If this is a COM class we allocate it using malloc.
2745 // This allows the reference counting to outlive the reference known about by the GC.
2747 p
= pureMalloc(init
.length
);
2749 onOutOfMemoryError();
2753 BlkAttr attr
= BlkAttr
.NONE
;
2755 /* `extern(C++)`` classes don't have a classinfo pointer in their vtable,
2756 * so the GC can't finalize them.
2758 static if (__traits(hasMember
, T
, "__dtor") && __traits(getLinkage
, T
) != "C++")
2759 attr |
= BlkAttr
.FINALIZE
;
2760 static if (!hasIndirections
!T
)
2761 attr |
= BlkAttr
.NO_SCAN
;
2763 p
= GC
.malloc(init
.length
, attr
, typeid(T
));
2764 debug(PRINTF
) printf(" p = %p\n", p
);
2769 printf("p = %p\n", p
);
2770 printf("init.ptr = %p, len = %llu\n", init
.ptr
, cast(ulong)init
.length
);
2771 printf("vptr = %p\n", *cast(void**) init
);
2772 printf("vtbl[0] = %p\n", (*cast(void***) init
)[0]);
2773 printf("vtbl[1] = %p\n", (*cast(void***) init
)[1]);
2774 printf("init[0] = %x\n", (cast(uint*) init
)[0]);
2775 printf("init[1] = %x\n", (cast(uint*) init
)[1]);
2776 printf("init[2] = %x\n", (cast(uint*) init
)[2]);
2777 printf("init[3] = %x\n", (cast(uint*) init
)[3]);
2778 printf("init[4] = %x\n", (cast(uint*) init
)[4]);
2782 p
[0 .. init
.length
] = cast(void[]) init
[];
2784 debug(PRINTF
) printf("initialization done\n");
2789 * TraceGC wrapper around $(REF _d_newclassT, core,lifetime).
2791 T
_d_newclassTTrace(T
)(string file
, int line
, string funcname
) @trusted
2793 version (D_TypeInfo
)
2795 import core
.internal
.array
.utils
: TraceHook
, gcStatsPure
, accumulatePure
;
2796 mixin(TraceHook
!(T
.stringof
, "_d_newclassT"));
2798 return _d_newclassT
!T();
2801 assert(0, "Cannot create new class if compiling without support for runtime type information!");
2805 * Allocate an initialized non-array item.
2807 * This is an optimization to avoid things needed for arrays like the __arrayPad(size).
2808 * Used to allocate struct instances on the heap.
2811 * struct Sz {int x = 0;}
2812 * struct Si {int x = 3;}
2816 * new Sz(); // uses zero-initialization
2817 * new Si(); // uses Si.init
2822 * newly allocated item
2824 T
* _d_newitemT(T
)() @trusted
2826 import core
.internal
.lifetime
: emplaceInitializer
;
2827 import core
.internal
.traits
: hasIndirections
;
2828 import core
.memory
: GC
;
2830 auto flags
= !hasIndirections
!T ? GC
.BlkAttr
.NO_SCAN
: GC
.BlkAttr
.NONE
;
2831 immutable tiSize
= TypeInfoSize
!T
;
2832 immutable itemSize
= T
.sizeof
;
2833 immutable totalSize
= itemSize
+ tiSize
;
2835 flags |
= GC
.BlkAttr
.STRUCTFINAL | GC
.BlkAttr
.FINALIZE
;
2837 auto blkInfo
= GC
.qalloc(totalSize
, flags
, null);
2838 auto p
= blkInfo
.base
;
2842 // The GC might not have cleared the padding area in the block.
2843 *cast(TypeInfo
*) (p
+ (itemSize
& ~(size_t
.sizeof
- 1))) = null;
2844 *cast(TypeInfo
*) (p
+ blkInfo
.size
- tiSize
) = cast() typeid(T
);
2847 emplaceInitializer(*(cast(T
*) p
));
2856 C c
= _d_newclassT
!C();
2861 // Test initializers
2865 class C
{ int x
, y
; }
2866 C c
= _d_newclassT
!C();
2872 class C
{ int x
= 2, y
= 3; }
2873 C c
= _d_newclassT
!C();
2884 S
* s
= _d_newitemT
!S();
2889 // Test initializers
2893 // zero-initialization
2894 struct S
{ int x
, y
; }
2895 S
* s
= _d_newitemT
!S();
2902 struct S
{ int x
= 2, y
= 3; }
2903 S
* s
= _d_newitemT
!S();
2910 // Test GC attributes
2911 version (CoreUnittest
)
2920 this(int x
) { this.x
= x
; }
2925 this(int x
) { this.x
[] = x
; }
2935 import core
.memory
: GC
;
2939 assert(GC
.getAttr(s1
) == GC
.BlkAttr
.NO_SCAN
);
2941 auto s2
= new S2(3);
2943 assert(GC
.getAttr(s2
) == GC
.BlkAttr
.NO_SCAN
);
2945 auto s3
= new S3(1);
2946 assert(s3
.x
== [1, 1, 1, 1]);
2947 assert(GC
.getAttr(s3
) == GC
.BlkAttr
.NO_SCAN
);
2948 debug(SENTINEL
) {} else
2949 assert(GC
.sizeOf(s3
) == 16);
2952 assert(s4
.x
== null);
2953 assert(GC
.getAttr(s4
) == 0);
2956 // Test struct finalizers exception handling
2957 debug(SENTINEL
) {} else
2960 import core
.memory
: GC
;
2964 import core
.exception
;
2968 ~this() { throw exc
; }
2971 bool caught
= false;
2972 S1
* s
= new S1(new E("test onFinalizeError"));
2975 GC
.runFinalizers((cast(char*)(typeid(S1
).xdtor
))[0 .. 1]);
2977 catch (FinalizeError err
)
2988 assert(test!Exception
);
2989 import core
.exception
: InvalidMemoryOperationError
;
2990 assert(!test!InvalidMemoryOperationError
);
2993 version (D_ProfileGC
)
2996 * TraceGC wrapper around $(REF _d_newitemT, core,lifetime).
2998 T
* _d_newitemTTrace(T
)(string file
, int line
, string funcname
) @trusted
3000 version (D_TypeInfo
)
3002 import core
.internal
.array
.utils
: TraceHook
, gcStatsPure
, accumulatePure
;
3003 mixin(TraceHook
!(T
.stringof
, "_d_newitemT"));
3005 return _d_newitemT
!T();
3008 assert(0, "Cannot create new `struct` if compiling without support for runtime type information!");
3012 template TypeInfoSize(T
)
3014 import core
.internal
.traits
: hasElaborateDestructor
;
3015 enum TypeInfoSize
= (is (T
== struct) && hasElaborateDestructor
!T
) ? size_t
.sizeof
: 0;