]> git.ipfire.org Git - thirdparty/gcc.git/blame - libphobos/libdruntime/core/lifetime.d
d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[thirdparty/gcc.git] / libphobos / libdruntime / core / lifetime.d
CommitLineData
5fee5ec3
IB
1module core.lifetime;
2
3import core.internal.attributes : betterC;
4
5// emplace
6/**
7Given a pointer `chunk` to uninitialized memory (but already typed
8as `T`), constructs an object of non-`class` type `T` at that
9address. If `T` is a class, initializes the class reference to null.
10Returns: A pointer to the newly constructed object (which is the same
11as `chunk`).
12 */
13T* emplace(T)(T* chunk) @safe pure nothrow
14{
15 import core.internal.lifetime : emplaceRef;
16
17 emplaceRef!T(*chunk);
18 return chunk;
19}
20
21///
22@betterC
23@system unittest
24{
25 static struct S
26 {
27 int i = 42;
28 }
29 S[2] s2 = void;
30 emplace(&s2);
31 assert(s2[0].i == 42 && s2[1].i == 42);
32}
33
34///
35@system unittest
36{
37 interface I {}
38 class K : I {}
39
40 K k = void;
41 emplace(&k);
42 assert(k is null);
43
44 I i = void;
45 emplace(&i);
46 assert(i is null);
47}
48
49/**
50Given a pointer `chunk` to uninitialized memory (but already typed
51as a non-class type `T`), constructs an object of type `T` at
52that address from arguments `args`. If `T` is a class, initializes
53the class reference to `args[0]`.
54This function can be `@trusted` if the corresponding constructor of
55`T` is `@safe`.
56Returns: A pointer to the newly constructed object (which is the same
57as `chunk`).
58 */
59T* emplace(T, Args...)(T* chunk, auto ref Args args)
60 if (is(T == struct) || Args.length == 1)
61{
62 import core.internal.lifetime : emplaceRef;
63
64 emplaceRef!T(*chunk, forward!args);
65 return chunk;
66}
67
68///
69@betterC
70@system unittest
71{
72 int a;
73 int b = 42;
74 assert(*emplace!int(&a, b) == 42);
75}
76
77@betterC
78@system unittest
79{
80 shared int i;
81 emplace(&i, 42);
82 assert(i == 42);
83}
84
85/**
86Given a raw memory area `chunk` (but already typed as a class type `T`),
87constructs an object of `class` type `T` at that address. The constructor
88is passed the arguments `Args`.
89If `T` is an inner class whose `outer` field can be used to access an instance
90of the enclosing class, then `Args` must not be empty, and the first member of it
91must be a valid initializer for that `outer` field. Correct initialization of
92this field is essential to access members of the outer class inside `T` methods.
93Note:
94This function is `@safe` if the corresponding constructor of `T` is `@safe`.
95Returns: The newly constructed object.
96 */
97T emplace(T, Args...)(T chunk, auto ref Args args)
98 if (is(T == class))
99{
100 import core.internal.traits : isInnerClass;
101
102 static assert(!__traits(isAbstractClass, T), T.stringof ~
103 " is abstract and it can't be emplaced");
104
105 // Initialize the object in its pre-ctor state
9c7d5e88
IB
106 const initializer = __traits(initSymbol, T);
107 (() @trusted { (cast(void*) chunk)[0 .. initializer.length] = initializer[]; })();
5fee5ec3
IB
108
109 static if (isInnerClass!T)
110 {
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");
115
116 chunk.outer = args[0];
117 alias args1 = args[1..$];
118 }
119 else alias args1 = args;
120
121 // Call the ctor if any
122 static if (is(typeof(chunk.__ctor(forward!args1))))
123 {
124 // T defines a genuine constructor accepting args
125 // Go the classic route: write .init first, then call ctor
126 chunk.__ctor(forward!args1);
127 }
128 else
129 {
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);
133 }
134 return chunk;
135}
136
137///
138@safe unittest
139{
140 () @safe {
141 class SafeClass
142 {
143 int x;
144 @safe this(int x) { this.x = x; }
145 }
146
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);
151
152 class UnsafeClass
153 {
154 int x;
155 @system this(int x) { this.x = x; }
156 }
157
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)));
162 }();
163}
164
165@safe unittest
166{
167 class Outer
168 {
169 int i = 3;
170 class Inner
171 {
172 @safe auto getI() { return i; }
173 }
174 }
175 auto outerBuf = new void[__traits(classInstanceSize, Outer)];
176 auto outerSupport = (() @trusted => cast(Outer)(outerBuf.ptr))();
177
178 auto innerBuf = new void[__traits(classInstanceSize, Outer.Inner)];
179 auto innerSupport = (() @trusted => cast(Outer.Inner)(innerBuf.ptr))();
180
181 auto inner = innerSupport.emplace!(Outer.Inner)(outerSupport.emplace!Outer);
182 assert(inner.getI == 3);
183}
184
185/**
186Given a raw memory area `chunk`, constructs an object of `class` type `T` at
187that address. The constructor is passed the arguments `Args`.
188If `T` is an inner class whose `outer` field can be used to access an instance
189of the enclosing class, then `Args` must not be empty, and the first member of it
190must be a valid initializer for that `outer` field. Correct initialization of
191this field is essential to access members of the outer class inside `T` methods.
192Preconditions:
193`chunk` must be at least as large as `T` needs and should have an alignment
194multiple of `T`'s alignment. (The size of a `class` instance is obtained by using
195$(D __traits(classInstanceSize, T))).
196Note:
197This function can be `@trusted` if the corresponding constructor of `T` is `@safe`.
198Returns: The newly constructed object.
199 */
200T emplace(T, Args...)(void[] chunk, auto ref Args args)
201 if (is(T == class))
202{
5fee5ec3
IB
203 enum classSize = __traits(classInstanceSize, T);
204 assert(chunk.length >= classSize, "chunk size too small.");
205
5eb9927a 206 enum alignment = __traits(classInstanceAlignment, T);
5fee5ec3
IB
207 assert((cast(size_t) chunk.ptr) % alignment == 0, "chunk is not aligned.");
208
209 return emplace!T(cast(T)(chunk.ptr), forward!args);
210}
211
212///
213@system unittest
214{
215 static class C
216 {
217 int i;
218 this(int i){this.i = i;}
219 }
220 auto buf = new void[__traits(classInstanceSize, C)];
221 auto c = emplace!C(buf, 5);
222 assert(c.i == 5);
223}
224
9c7d5e88
IB
225///
226@betterC
227@nogc pure nothrow @system unittest
228{
229 // works with -betterC too:
230
231 static extern (C++) class C
232 {
233 @nogc pure nothrow @safe:
234 int i = 3;
235 this(int i)
236 {
237 assert(this.i == 3);
238 this.i = i;
239 }
240 int virtualGetI() { return i; }
241 }
242
5eb9927a 243 align(__traits(classInstanceAlignment, C)) byte[__traits(classInstanceSize, C)] buffer;
9c7d5e88
IB
244 C c = emplace!C(buffer[], 42);
245 assert(c.virtualGetI() == 42);
246}
247
5fee5ec3
IB
248@system unittest
249{
250 class Outer
251 {
252 int i = 3;
253 class Inner
254 {
255 auto getI() { return i; }
256 }
257 }
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);
262}
263
264@nogc pure nothrow @safe unittest
265{
266 static class __conv_EmplaceTestClass
267 {
268 @nogc @safe pure nothrow:
269 int i = 3;
270 this(int i)
271 {
272 assert(this.i == 3);
273 this.i = 10 + i;
274 }
275 this(ref int i)
276 {
277 assert(this.i == 3);
278 this.i = 20 + i;
279 }
280 this(int i, ref int j)
281 {
282 assert(this.i == 3 && i == 5 && j == 6);
283 this.i = i;
284 ++j;
285 }
286 }
287
288 int var = 6;
5eb9927a
IB
289 align(__traits(classInstanceAlignment, __conv_EmplaceTestClass))
290 ubyte[__traits(classInstanceSize, __conv_EmplaceTestClass)] buf;
5fee5ec3
IB
291 auto support = (() @trusted => cast(__conv_EmplaceTestClass)(buf.ptr))();
292
293 auto fromRval = emplace!__conv_EmplaceTestClass(support, 1);
294 assert(fromRval.i == 11);
295
296 auto fromLval = emplace!__conv_EmplaceTestClass(support, var);
297 assert(fromLval.i == 26);
298
299 auto k = emplace!__conv_EmplaceTestClass(support, 5, var);
300 assert(k.i == 5);
301 assert(var == 7);
302}
303
304/**
305Given a raw memory area `chunk`, constructs an object of non-$(D
306class) type `T` at that address. The constructor is passed the
307arguments `args`, if any.
308Preconditions:
309`chunk` must be at least as large
310as `T` needs and should have an alignment multiple of `T`'s
311alignment.
312Note:
313This function can be `@trusted` if the corresponding constructor of
314`T` is `@safe`.
315Returns: A pointer to the newly constructed object.
316 */
317T* emplace(T, Args...)(void[] chunk, auto ref Args args)
318 if (!is(T == class))
319{
320 import core.internal.traits : Unqual;
321 import core.internal.lifetime : emplaceRef;
322
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.");
325
326 emplaceRef!(T, Unqual!T)(*cast(Unqual!T*) chunk.ptr, forward!args);
327 return cast(T*) chunk.ptr;
328}
329
330///
331@betterC
332@system unittest
333{
334 struct S
335 {
336 int a, b;
337 }
338 void[S.sizeof] buf = void;
339 S s;
340 s.a = 42;
341 s.b = 43;
342 auto s1 = emplace!S(buf, s);
343 assert(s1.a == 42 && s1.b == 43);
344}
345
346// Bulk of emplace unittests starts here
347
348@betterC
349@system unittest /* unions */
350{
351 static union U
352 {
353 string a;
354 int b;
355 struct
356 {
357 long c;
358 int[] d;
359 }
360 }
361 U u1 = void;
362 U u2 = { "hello" };
363 emplace(&u1, u2);
364 assert(u1.a == "hello");
365}
366
e9251fea 367@system unittest // https://issues.dlang.org/show_bug.cgi?id=15772
5fee5ec3
IB
368{
369 abstract class Foo {}
370 class Bar: Foo {}
371 void[] memory;
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))));
378}
379
380@betterC
381@system unittest
382{
383 struct S { @disable this(); }
384 S s = void;
385 static assert(!__traits(compiles, emplace(&s)));
386 emplace(&s, S.init);
387}
388
389@betterC
390@system unittest
391{
392 struct S1
393 {}
394
395 struct S2
396 {
397 void opAssign(S2);
398 }
399
400 S1 s1 = void;
401 S2 s2 = void;
402 S1[2] as1 = void;
403 S2[2] as2 = void;
404 emplace(&s1);
405 emplace(&s2);
406 emplace(&as1);
407 emplace(&as2);
408}
409
410@system unittest
411{
412 static struct S1
413 {
414 this(this) @disable;
415 }
416 static struct S2
417 {
418 this() @disable;
419 }
420 S1[2] ss1 = void;
421 S2[2] ss2 = void;
422 emplace(&ss1);
423 static assert(!__traits(compiles, emplace(&ss2)));
424 S1 s1 = S1.init;
425 S2 s2 = S2.init;
426 static assert(!__traits(compiles, emplace(&ss1, s1)));
427 emplace(&ss2, s2);
428}
429
430@system unittest
431{
432 struct S
433 {
434 immutable int i;
435 }
436 S s = void;
437 S[2] ss1 = void;
438 S[2] ss2 = void;
439 emplace(&s, 5);
440 assert(s.i == 5);
441 emplace(&ss1, s);
442 assert(ss1[0].i == 5 && ss1[1].i == 5);
443 emplace(&ss2, ss1);
444 assert(ss2 == ss1);
445}
446
447//Start testing emplace-args here
448
449@system unittest
450{
451 interface I {}
452 class K : I {}
453
454 K k = null, k2 = new K;
455 assert(k !is k2);
456 emplace!K(&k, k2);
457 assert(k is k2);
458
459 I i = null;
460 assert(i !is k);
461 emplace!I(&i, k);
462 assert(i is k);
463}
464
465@system unittest
466{
467 static struct S
468 {
469 int i = 5;
470 void opAssign(S){assert(0);}
471 }
472 S[2] sa = void;
473 S[2] sb;
474 emplace(&sa, sb);
475 assert(sa[0].i == 5 && sa[1].i == 5);
476}
477
478//Start testing emplace-struct here
479
480// Test constructor branch
481@betterC
482@system unittest
483{
484 struct S
485 {
486 double x = 5, y = 6;
487 this(int a, int b)
488 {
489 assert(x == 5 && y == 6);
490 x = a;
491 y = b;
492 }
493 }
494
495 void[S.sizeof] s1 = void;
496 auto s2 = S(42, 43);
497 assert(*emplace!S(cast(S*) s1.ptr, s2) == s2);
498 assert(*emplace!S(cast(S*) s1, 44, 45) == S(44, 45));
499}
500
501@system unittest
502{
503 static struct __conv_EmplaceTest
504 {
505 int i = 3;
506 this(int i)
507 {
508 assert(this.i == 3 && i == 5);
509 this.i = i;
510 }
511 this(int i, ref int j)
512 {
513 assert(i == 5 && j == 6);
514 this.i = i;
515 ++j;
516 }
517
518 @disable:
519 this();
520 this(this);
521 void opAssign();
522 }
523
524 __conv_EmplaceTest k = void;
525 emplace(&k, 5);
526 assert(k.i == 5);
527
528 int var = 6;
529 __conv_EmplaceTest x = void;
530 emplace(&x, 5, var);
531 assert(x.i == 5);
532 assert(var == 7);
533
534 var = 6;
535 auto z = emplace!__conv_EmplaceTest(new void[__conv_EmplaceTest.sizeof], 5, var);
536 assert(z.i == 5);
537 assert(var == 7);
538}
539
540// Test matching fields branch
541@betterC
542@system unittest
543{
544 struct S { uint n; }
545 S s;
546 emplace!S(&s, 2U);
547 assert(s.n == 2);
548}
549
550@betterC
551@safe unittest
552{
553 struct S { int a, b; this(int){} }
554 S s;
555 static assert(!__traits(compiles, emplace!S(&s, 2, 3)));
556}
557
558@betterC
559@system unittest
560{
561 struct S { int a, b = 7; }
562 S s1 = void, s2 = void;
563
564 emplace!S(&s1, 2);
565 assert(s1.a == 2 && s1.b == 7);
566
567 emplace!S(&s2, 2, 3);
568 assert(s2.a == 2 && s2.b == 3);
569}
570
571//opAssign
572@betterC
573@system unittest
574{
575 static struct S
576 {
577 int i = 5;
578 void opAssign(int){assert(0);}
579 void opAssign(S){assert(0);}
580 }
581 S sa1 = void;
582 S sa2 = void;
583 S sb1 = S(1);
584 emplace(&sa1, sb1);
585 emplace(&sa2, 2);
586 assert(sa1.i == 1);
587 assert(sa2.i == 2);
588}
589
590//postblit precedence
591@betterC
592@system unittest
593{
594 //Works, but breaks in "-w -O" because of @@@9332@@@.
595 //Uncomment test when 9332 is fixed.
596 static struct S
597 {
598 int i;
599
600 this(S other){assert(false);}
601 this(int i){this.i = i;}
602 this(this){}
603 }
604 S a = void;
605 assert(is(typeof({S b = a;}))); //Postblit
606 assert(is(typeof({S b = S(a);}))); //Constructor
607 auto b = S(5);
608 emplace(&a, b);
609 assert(a.i == 5);
610
611 static struct S2
612 {
613 int* p;
614 this(const S2){}
615 }
616 static assert(!is(immutable S2 : S2));
617 S2 s2 = void;
618 immutable is2 = (immutable S2).init;
619 emplace(&s2, is2);
620}
621
622//nested structs and postblit
623@system unittest
624{
625 static struct S
626 {
627 int* p;
628 this(int i){p = [i].ptr;}
629 this(this)
630 {
631 if (p)
632 p = [*p].ptr;
633 }
634 }
635 static struct SS
636 {
637 S s;
638 void opAssign(const SS)
639 {
640 assert(0);
641 }
642 }
643 SS ssa = void;
644 SS ssb = SS(S(5));
645 emplace(&ssa, ssb);
646 assert(*ssa.s.p == 5);
647 assert(ssa.s.p != ssb.s.p);
648}
649
650//disabled postblit
651@betterC
652@system unittest
653{
654 static struct S1
655 {
656 int i;
657 @disable this(this);
658 }
659 S1 s1 = void;
660 emplace(&s1, 1);
661 assert(s1.i == 1);
662 static assert(!__traits(compiles, emplace(&s1, s1))); // copy disabled
663 static assert(__traits(compiles, emplace(&s1, move(s1)))); // move not affected
664
665 static struct S2
666 {
667 int i;
668 @disable this(this);
669 this(ref S2){}
670 }
671 S2 s2 = void;
672 //static assert(!__traits(compiles, emplace(&s2, 1)));
673 emplace(&s2, S2.init);
674
675 static struct SS1
676 {
677 S1 s;
678 }
679 SS1 ss1 = void;
680 emplace(&ss1);
681 static assert(!__traits(compiles, emplace(&ss1, ss1))); // copying disabled
682 static assert(__traits(compiles, emplace(&ss1, move(ss1)))); // move unaffected
683
684 static struct SS2
685 {
686 S2 s;
687 }
688 SS2 ss2 = void;
689 emplace(&ss2);
690 static assert(!__traits(compiles, emplace(&ss2, ss2))); // copying disabled
691 static assert(__traits(compiles, emplace(&ss2, SS2.init))); // move is OK
692
693
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)));
699}
700
701//Imutability
702@betterC
703@system unittest
704{
705 //Castable immutability
706 {
707 static struct S1
708 {
709 int i;
710 }
711 static assert(is( immutable(S1) : S1));
712 S1 sa = void;
713 auto sb = immutable(S1)(5);
714 emplace(&sa, sb);
715 assert(sa.i == 5);
716 }
717 //Un-castable immutability
718 {
719 static struct S2
720 {
721 int* p;
722 }
723 static assert(!is(immutable(S2) : S2));
724 S2 sa = void;
725 auto sb = immutable(S2)(null);
726 assert(!__traits(compiles, emplace(&sa, sb)));
727 }
728}
729
730@betterC
731@system unittest
732{
733 static struct S
734 {
735 immutable int i;
736 immutable(int)* j;
737 }
738 S s = void;
739 emplace(&s, 1, null);
740 emplace(&s, 2, &s.i);
741 assert(s is S(2, &s.i));
742}
743
744//Context pointer
745@system unittest
746{
747 int i = 0;
748 {
749 struct S1
750 {
751 void foo(){++i;}
752 }
753 S1 sa = void;
754 S1 sb;
755 emplace(&sa, sb);
756 sa.foo();
757 assert(i == 1);
758 }
759 {
760 struct S2
761 {
762 void foo(){++i;}
763 this(this){}
764 }
765 S2 sa = void;
766 S2 sb;
767 emplace(&sa, sb);
768 sa.foo();
769 assert(i == 2);
770 }
771}
772
773//Alias this
774@betterC
775@system unittest
776{
777 static struct S
778 {
779 int i;
780 }
781 //By Ref
782 {
783 static struct SS1
784 {
785 int j;
786 S s;
787 alias s this;
788 }
789 S s = void;
790 SS1 ss = SS1(1, S(2));
791 emplace(&s, ss);
792 assert(s.i == 2);
793 }
794 //By Value
795 {
796 static struct SS2
797 {
798 int j;
799 S s;
800 S foo() @property{return s;}
801 alias foo this;
802 }
803 S s = void;
804 SS2 ss = SS2(1, S(2));
805 emplace(&s, ss);
806 assert(s.i == 2);
807 }
808}
809
810version (CoreUnittest)
811{
812 //Ambiguity
813 private struct __std_conv_S
814 {
815 int i;
816 this(__std_conv_SS ss) {assert(0);}
817 static opCall(__std_conv_SS ss)
818 {
819 __std_conv_S s; s.i = ss.j;
820 return s;
821 }
822 }
823 private struct __std_conv_SS
824 {
825 int j;
826 __std_conv_S s;
827 ref __std_conv_S foo() return @property {s.i = j; return s;}
828 alias foo this;
829 }
830}
831
832@system unittest
833{
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);
837
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"
840 assert(s.i == 1);
841}
842
843//Nested classes
844@system unittest
845{
846 class A{}
847 static struct S
848 {
849 A a;
850 }
851 S s1 = void;
852 S s2 = S(new A);
853 emplace(&s1, s2);
854 assert(s1.a is s2.a);
855}
856
857//safety & nothrow & CTFE
858@betterC
859@system unittest
860{
861 //emplace should be safe for anything with no elaborate opassign
862 static struct S1
863 {
864 int i;
865 }
866 static struct S2
867 {
868 int i;
869 this(int j)@safe nothrow{i = j;}
870 }
871
872 int i;
873 S1 s1 = void;
874 S2 s2 = void;
875
876 auto pi = &i;
877 auto ps1 = &s1;
878 auto ps2 = &s2;
879
880 void foo() @safe nothrow
881 {
882 emplace(pi);
883 emplace(pi, 5);
884 emplace(ps1);
885 emplace(ps1, 5);
886 emplace(ps1, S1.init);
887 emplace(ps2);
888 emplace(ps2, 5);
889 emplace(ps2, S2.init);
890 }
891 foo();
892
893 T bar(T)() @property
894 {
895 T t/+ = void+/; //CTFE void illegal
896 emplace(&t, 5);
897 return t;
898 }
899 // CTFE
900 enum a = bar!int;
901 static assert(a == 5);
902 enum b = bar!S1;
903 static assert(b.i == 5);
904 enum c = bar!S2;
905 static assert(c.i == 5);
906 // runtime
907 auto aa = bar!int;
908 assert(aa == 5);
909 auto bb = bar!S1;
910 assert(bb.i == 5);
911 auto cc = bar!S2;
912 assert(cc.i == 5);
913}
914
915@betterC
916@system unittest
917{
918 struct S
919 {
920 int[2] get(){return [1, 2];}
921 alias get this;
922 }
923 struct SS
924 {
925 int[2] ii;
926 }
927 struct ISS
928 {
929 int[2] ii;
930 }
931 S s;
932 SS ss = void;
933 ISS iss = void;
934 emplace(&ss, s);
935 emplace(&iss, s);
936 assert(ss.ii == [1, 2]);
937 assert(iss.ii == [1, 2]);
938}
939
940//disable opAssign
941@betterC
942@system unittest
943{
944 static struct S
945 {
946 @disable void opAssign(S);
947 }
948 S s;
949 emplace(&s, S.init);
950}
951
952//opCall
953@betterC
954@system unittest
955{
956 int i;
957 //Without constructor
958 {
959 static struct S1
960 {
961 int i;
962 static S1 opCall(int*){assert(0);}
963 }
964 S1 s = void;
965 static assert(!__traits(compiles, emplace(&s, 1)));
966 }
967 //With constructor
968 {
969 static struct S2
970 {
971 int i = 0;
972 static S2 opCall(int*){assert(0);}
973 static S2 opCall(int){assert(0);}
974 this(int i){this.i = i;}
975 }
976 S2 s = void;
977 emplace(&s, 1);
978 assert(s.i == 1);
979 }
980 //With postblit ambiguity
981 {
982 static struct S3
983 {
984 int i = 0;
985 static S3 opCall(ref S3){assert(0);}
986 }
987 S3 s = void;
988 emplace(&s, S3.init);
989 }
990}
991
992//static arrays
993@system unittest
994{
995 static struct S
996 {
997 int[2] ii;
998 }
999 static struct IS
1000 {
1001 immutable int[2] ii;
1002 }
1003 int[2] ii;
1004 S s = void;
1005 IS ims = void;
1006 ubyte ub = 2;
1007 emplace(&s, ub);
1008 emplace(&s, ii);
1009 emplace(&ims, ub);
1010 emplace(&ims, ii);
1011 uint[2] uu;
1012 static assert(!__traits(compiles, {S ss = S(uu);}));
1013 static assert(!__traits(compiles, emplace(&s, uu)));
1014}
1015
1016@system unittest
1017{
1018 int[2] sii;
1019 int[2] sii2;
1020 uint[2] uii;
1021 uint[2] uii2;
1022 emplace(&sii, 1);
1023 emplace(&sii, 1U);
1024 emplace(&uii, 1);
1025 emplace(&uii, 1U);
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[]);
1034}
1035
1036@system unittest
1037{
1038 bool allowDestruction = false;
1039 struct S
1040 {
1041 int i;
1042 this(this){}
1043 ~this(){assert(allowDestruction);}
1044 }
1045 S s = S(1);
1046 S[2] ss1 = void;
1047 S[2] ss2 = void;
1048 S[2] ss3 = void;
1049 emplace(&ss1, s);
1050 emplace(&ss2, ss1);
1051 emplace(&ss3, ss2[]);
1052 assert(ss1[1] == s);
1053 assert(ss2[1] == s);
1054 assert(ss3[1] == s);
1055 allowDestruction = true;
1056}
1057
1058@system unittest
1059{
1060 //Checks postblit, construction, and context pointer
1061 int count = 0;
1062 struct S
1063 {
1064 this(this)
1065 {
1066 ++count;
1067 }
1068 ~this()
1069 {
1070 --count;
1071 }
1072 }
1073
1074 S s;
1075 {
1076 S[4] ss = void;
1077 emplace(&ss, s);
1078 assert(count == 4);
1079 }
1080 assert(count == 0);
1081}
1082
1083@system unittest
1084{
1085 struct S
1086 {
1087 int i;
1088 }
1089 S s;
1090 S[2][2][2] sss = void;
1091 emplace(&sss, s);
1092}
1093
1094@system unittest //Constness
1095{
1096 import core.internal.lifetime : emplaceRef;
1097
1098 int a = void;
1099 emplaceRef!(const int)(a, 5);
1100
1101 immutable i = 5;
1102 const(int)* p = void;
1103 emplaceRef!(const int*)(p, &i);
1104
1105 struct S
1106 {
1107 int* p;
1108 }
1109 alias IS = immutable(S);
1110 S s = void;
1111 emplaceRef!IS(s, IS());
1112 S[2] ss = void;
1113 emplaceRef!(IS[2])(ss, IS());
1114
1115 IS[2] iss = IS.init;
1116 emplaceRef!(IS[2])(ss, iss);
1117 emplaceRef!(IS[2])(ss, iss[]);
1118}
1119
1120@betterC
1121pure nothrow @safe @nogc unittest
1122{
1123 import core.internal.lifetime : emplaceRef;
1124
1125 int i;
1126 emplaceRef(i);
1127 emplaceRef!int(i);
1128 emplaceRef(i, 5);
1129 emplaceRef!int(i, 5);
1130}
1131
1132// Test attribute propagation for UDTs
1133pure nothrow @safe /* @nogc */ unittest
1134{
1135 import core.internal.lifetime : emplaceRef;
1136
1137 static struct Safe
1138 {
1139 this(this) pure nothrow @safe @nogc {}
1140 }
1141
1142 Safe safe = void;
1143 emplaceRef(safe, Safe());
1144
1145 Safe[1] safeArr = [Safe()];
1146 Safe[1] uninitializedSafeArr = void;
1147 emplaceRef(uninitializedSafeArr, safe);
1148 emplaceRef(uninitializedSafeArr, safeArr);
1149
1150 static struct Unsafe
1151 {
1152 this(this) @system {}
1153 }
1154
1155 Unsafe unsafe = void;
1156 static assert(!__traits(compiles, emplaceRef(unsafe, unsafe)));
1157
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)));
1162}
1163
1164@betterC
1165@system unittest
1166{
1167 // Issue 15313
1168 static struct Node
1169 {
1170 int payload;
1171 Node* next;
1172 uint refs;
1173 }
1174
1175 import core.stdc.stdlib : malloc;
1176 void[] buf = malloc(Node.sizeof)[0 .. Node.sizeof];
1177
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);
1182}
1183
1184@system unittest
1185{
1186 class A
1187 {
1188 int x = 5;
1189 int y = 42;
1190 this(int z)
1191 {
1192 assert(x == 5 && y == 42);
1193 x = y = z;
1194 }
1195 }
1196 void[] buf;
1197
5eb9927a 1198 static align(__traits(classInstanceAlignment, A)) byte[__traits(classInstanceSize, A)] sbuf;
5fee5ec3
IB
1199 buf = sbuf[];
1200 auto a = emplace!A(buf, 55);
1201 assert(a.x == 55 && a.y == 55);
1202
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);
1207
1208 // need ctor args
1209 static assert(!is(typeof(emplace!A(buf))));
1210}
1211
1212//constructor arguments forwarding
1213@betterC
1214@system unittest
1215{
1216 static struct S
1217 {
1218 this()(auto ref long arg)
1219 {
1220 // assert that arg is an lvalue
1221 static assert(__traits(isRef, arg));
1222 }
1223 this()(auto ref double arg)
1224 // assert that arg is an rvalue
1225 {
1226 static assert(!__traits(isRef, arg));
1227 }
1228 }
1229 S obj = void;
1230 long i;
1231 emplace(&obj, i); // lvalue
1232 emplace(&obj, 0.0); // rvalue
1233}
1234// Bulk of emplace unittests ends here
1235
1236/**
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.
1240 *
1241 * Params:
1242 * source = value to be copied into target
1243 * target = uninitialized value to be initialized with a copy of source
1244 */
1245void copyEmplace(S, T)(ref S source, ref T target) @system
1246 if (is(immutable S == immutable T))
1247{
1248 import core.internal.traits : BaseElemOf, hasElaborateCopyConstructor, Unconst, Unqual;
1249
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; }))
1252 {
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);
1256 }
1257
1258 void blit()
1259 {
1260 import core.stdc.string : memcpy;
1261 memcpy(cast(Unqual!(T)*) &target, cast(Unqual!(T)*) &source, T.sizeof);
1262 }
1263
1264 static if (is(T == struct))
1265 {
1266 static if (__traits(hasPostblit, T))
1267 {
1268 blit();
1269 (cast() target).__xpostblit();
1270 }
1271 else static if (__traits(hasCopyConstructor, T))
1272 {
31350635
IB
1273 // https://issues.dlang.org/show_bug.cgi?id=22766
1274 import core.internal.lifetime : emplaceInitializer;
1275 emplaceInitializer(*(cast(Unqual!T*)&target));
5fee5ec3
IB
1276 static if (__traits(isNested, T))
1277 {
1278 // copy context pointer
1279 *(cast(void**) &target.tupleof[$-1]) = cast(void*) source.tupleof[$-1];
1280 }
1281 target.__ctor(source); // invoke copy ctor
1282 }
1283 else
1284 {
1285 blit(); // no opAssign
1286 }
1287 }
1288 else static if (is(T == E[n], E, size_t n))
1289 {
1290 static if (hasElaborateCopyConstructor!E)
1291 {
1292 size_t i;
1293 try
1294 {
1295 for (i = 0; i < n; i++)
1296 copyEmplace(source[i], target[i]);
1297 }
1298 catch (Exception e)
1299 {
1300 // destroy, in reverse order, what we've constructed so far
1301 while (i--)
1302 destroy(*cast(Unconst!(E)*) &target[i]);
1303 throw e;
1304 }
1305 }
1306 else // trivial copy
1307 {
1308 blit(); // all elements at once
1309 }
1310 }
1311 else
1312 {
1313 *cast(Unconst!(T)*) &target = *cast(Unconst!(T)*) &source;
1314 }
1315}
1316
1317///
1318@betterC
1319@system pure nothrow @nogc unittest
1320{
1321 int source = 123;
1322 int target = void;
1323 copyEmplace(source, target);
1324 assert(target == 123);
1325}
1326
1327///
1328@betterC
1329@system pure nothrow @nogc unittest
1330{
1331 immutable int[1][1] source = [ [123] ];
1332 immutable int[1][1] target = void;
1333 copyEmplace(source, target);
1334 assert(target[0][0] == 123);
1335}
1336
1337///
1338@betterC
1339@system pure nothrow @nogc unittest
1340{
1341 struct S
1342 {
1343 int x;
1344 void opAssign(const scope ref S rhs) @safe pure nothrow @nogc
1345 {
1346 assert(0);
1347 }
1348 }
1349
1350 S source = S(42);
1351 S target = void;
1352 copyEmplace(source, target);
1353 assert(target.x == 42);
1354}
1355
1356// preserve shared-ness
1357@system pure nothrow unittest
1358{
1359 auto s = new Object();
1360 auto ss = new shared Object();
1361
1362 Object t;
1363 shared Object st;
1364
1365 copyEmplace(s, t);
1366 assert(t is s);
1367
1368 copyEmplace(ss, st);
1369 assert(st is ss);
1370
1371 static assert(!__traits(compiles, copyEmplace(s, st)));
1372 static assert(!__traits(compiles, copyEmplace(ss, t)));
1373}
1374
31350635
IB
1375// https://issues.dlang.org/show_bug.cgi?id=22766
1376@system pure nothrow @nogc unittest
1377{
1378 static struct S
1379 {
1380 @disable this();
1381 this(int) @safe pure nothrow @nogc{}
1382 this(ref const(S) other) @safe pure nothrow @nogc {}
1383 }
1384
1385 S s1 = S(1);
1386 S s2 = void;
1387 copyEmplace(s1, s2);
1388 assert(s2 == S(1));
1389}
1390
5fee5ec3
IB
1391version (DigitalMars) version (X86) version (Posix) version = DMD_X86_Posix;
1392
1393// don't violate immutability for reference types
1394@system pure nothrow unittest
1395{
1396 auto s = new Object();
1397 auto si = new immutable Object();
1398
1399 Object t;
1400 immutable Object ti;
1401
1402 copyEmplace(s, t);
1403 assert(t is s);
1404
1405 copyEmplace(si, ti);
1406 version (DMD_X86_Posix) { /* wrongly fails without -O */ } else
1407 assert(ti is si);
1408
1409 static assert(!__traits(compiles, copyEmplace(s, ti)));
1410 static assert(!__traits(compiles, copyEmplace(si, t)));
1411}
1412
1413version (CoreUnittest)
1414{
1415 private void testCopyEmplace(S, T)(const scope T* expected = null)
1416 {
1417 S source;
1418 T target = void;
1419 copyEmplace(source, target);
1420 if (expected)
1421 assert(target == *expected);
1422 else
1423 {
1424 T expectedCopy = source;
1425 assert(target == expectedCopy);
1426 }
1427 }
1428}
1429
1430// postblit
1431@system pure nothrow @nogc unittest
1432{
1433 static struct S
1434 {
1435 @safe pure nothrow @nogc:
1436 int x = 42;
1437 this(this) { x += 10; }
1438 }
1439
1440 testCopyEmplace!(S, S)();
1441 testCopyEmplace!(immutable S, S)();
1442 testCopyEmplace!(S, immutable S)();
1443 testCopyEmplace!(immutable S, immutable S)();
1444
1445 testCopyEmplace!(S[1], S[1])();
1446 testCopyEmplace!(immutable S[1], S[1])();
1447
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);
1453}
1454
1455// copy constructors
1456@system pure nothrow @nogc unittest
1457{
1458 static struct S
1459 {
1460 @safe pure nothrow @nogc:
1461 int x = 42;
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; }
1465 }
1466
1467 testCopyEmplace!(S, S)();
1468 testCopyEmplace!(immutable S, S)();
1469 testCopyEmplace!(S, immutable S)();
1470 testCopyEmplace!(immutable S, immutable S)();
1471
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);
1480}
1481
1482// copy constructor in nested struct
1483@system pure nothrow unittest
1484{
1485 int copies;
1486 struct S
1487 {
1488 @safe pure nothrow @nogc:
1489 size_t x = 42;
1490 this(size_t x) { this.x = x; }
1491 this(const scope ref S rhs)
1492 {
1493 assert(x == 42); // T.init
1494 x = rhs.x;
1495 ++copies;
1496 }
1497 }
1498
1499 {
1500 copies = 0;
1501 S source = S(123);
1502 immutable S target = void;
1503 copyEmplace(source, target);
1504 assert(target is source);
1505 assert(copies == 1);
1506 }
1507
1508 {
1509 copies = 0;
1510 immutable S[1] source = [immutable S(456)];
1511 S[1] target = void;
1512 copyEmplace(source, target);
1513 assert(target[0] is source[0]);
1514 assert(copies == 1);
1515 }
1516}
1517
1518// destruction of partially copied static array
1519@system unittest
1520{
1521 static struct S
1522 {
1523 __gshared int[] deletions;
1524 int x;
1525 this(this) { if (x == 5) throw new Exception(""); }
1526 ~this() { deletions ~= x; }
1527 }
1528
1529 alias T = immutable S[3][2];
1530 T source = [ [S(1), S(2), S(3)], [S(4), S(5), S(6)] ];
1531 T target = void;
1532 try
1533 {
1534 copyEmplace(source, target);
1535 assert(0);
1536 }
1537 catch (Exception)
1538 {
1539 static immutable expectedDeletions = [ 4, 3, 2, 1 ];
1540 version (DigitalMars)
1541 {
1542 assert(S.deletions == expectedDeletions ||
1543 S.deletions == [ 4 ]); // FIXME: happens with -O
1544 }
1545 else
1546 assert(S.deletions == expectedDeletions);
1547 }
1548}
1549
1550/**
1551Forwards function arguments while keeping `out`, `ref`, and `lazy` on
1552the parameters.
1553
1554Params:
1555 args = a parameter list or an $(REF AliasSeq,std,meta).
1556Returns:
1557 An `AliasSeq` of `args` with `out`, `ref`, and `lazy` saved.
1558*/
1559template forward(args...)
1560{
1561 import core.internal.traits : AliasSeq;
1562
b3f58f87 1563 template fwd(alias arg)
5fee5ec3 1564 {
5fee5ec3
IB
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))))
1570 alias fwd = arg;
1571 // (r)value
1572 else
d77c2804
IB
1573 @property auto fwd()
1574 {
1575 version (DigitalMars) { /* @@BUG 23890@@ */ } else pragma(inline, true);
1576 return move(arg);
1577 }
5fee5ec3 1578 }
b3f58f87
IB
1579
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];
5fee5ec3 1585 else
b3f58f87 1586 alias forward = Result;
5fee5ec3
IB
1587}
1588
1589///
1590@safe unittest
1591{
1592 class C
1593 {
1594 static int foo(int n) { return 1; }
1595 static int foo(ref int n) { return 2; }
1596 }
1597
1598 // with forward
1599 int bar()(auto ref int x) { return C.foo(forward!x); }
1600
1601 // without forward
1602 int baz()(auto ref int x) { return C.foo(x); }
1603
1604 int i;
1605 assert(bar(1) == 1);
1606 assert(bar(i) == 2);
1607
1608 assert(baz(1) == 2);
1609 assert(baz(i) == 2);
1610}
1611
1612///
1613@safe unittest
1614{
1615 void foo(int n, ref string s) { s = null; foreach (i; 0 .. n) s ~= "Hello"; }
1616
1617 // forwards all arguments which are bound to parameter tuple
1618 void bar(Args...)(auto ref Args args) { return foo(forward!args); }
1619
1620 // forwards all arguments with swapping order
1621 void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); }
1622
1623 string s;
1624 bar(1, s);
1625 assert(s == "Hello");
1626 baz(s, 2);
1627 assert(s == "HelloHello");
1628}
1629
1630@safe unittest
1631{
1632 auto foo(TL...)(auto ref TL args)
1633 {
1634 string result = "";
1635 foreach (i, _; args)
1636 {
1637 //pragma(msg, "[",i,"] ", __traits(isRef, args[i]) ? "L" : "R");
1638 result ~= __traits(isRef, args[i]) ? "L" : "R";
1639 }
1640 return result;
1641 }
1642
1643 string bar(TL...)(auto ref TL args)
1644 {
1645 return foo(forward!args);
1646 }
1647 string baz(TL...)(auto ref TL args)
1648 {
1649 int x;
1650 return foo(forward!args[3], forward!args[2], 1, forward!args[1], forward!args[0], x);
1651 }
1652
1653 struct S {}
1654 S makeS(){ return S(); }
1655 int n;
1656 string s;
1657 assert(bar(S(), makeS(), n, s) == "RRLL");
1658 assert(baz(S(), makeS(), n, s) == "LLRRRL");
1659}
1660
1661@betterC
1662@safe unittest
1663{
1664 ref int foo(return ref int a) { return a; }
1665 ref int bar(Args)(auto ref Args args)
1666 {
1667 return foo(forward!args);
1668 }
1669 static assert(!__traits(compiles, { auto x1 = bar(3); })); // case of NG
1670 int value = 3;
1671 auto x2 = bar(value); // case of OK
1672}
1673
1674///
1675@betterC
1676@safe unittest
1677{
1678 struct X {
1679 int i;
1680 this(this)
1681 {
1682 ++i;
1683 }
1684 }
1685
1686 struct Y
1687 {
1688 private X x_;
1689 this()(auto ref X x)
1690 {
1691 x_ = forward!x;
1692 }
1693 }
1694
1695 struct Z
1696 {
1697 private const X x_;
1698 this()(auto ref X x)
1699 {
1700 x_ = forward!x;
1701 }
1702 this()(auto const ref X x)
1703 {
1704 x_ = forward!x;
1705 }
1706 }
1707
1708 X x;
1709 const X cx;
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(); }));
1719
1720
1721 Y y1 = x;
1722 // ref lvalue, copy
1723 assert(y1.x_.i == 1);
1724 Y y2 = X();
1725 // rvalue, move
1726 assert(y2.x_.i == 0);
1727
1728 Z z1 = x;
1729 // ref lvalue, copy
1730 assert(z1.x_.i == 1);
1731 Z z2 = X();
1732 // rvalue, move
1733 assert(z2.x_.i == 0);
1734 Z z3 = cx;
1735 // ref const lvalue, copy
1736 assert(z3.x_.i == 1);
1737 Z z4 = constX();
1738 // const rvalue, copy
1739 assert(z4.x_.i == 1);
1740}
1741
1742// lazy -> lazy
1743@betterC
1744@safe unittest
1745{
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); }
1749
1750 int numCalls = 0;
1751 assert(foo3({ ++numCalls; return 42; }()) == 42);
1752 assert(numCalls == 1);
1753}
1754
1755// lazy -> non-lazy
1756@betterC
1757@safe unittest
1758{
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); }
1762
1763 int numCalls;
1764 assert(foo3(11, { ++numCalls; return 31; }()) == 42);
1765 assert(numCalls == 1);
1766}
1767
1768// non-lazy -> lazy
1769@betterC
1770@safe unittest
1771{
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); }
1775
1776 assert(foo3(11, 31) == 42);
1777}
1778
1779// out
1780@betterC
1781@safe unittest
1782{
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); }
1786
1787 int b;
1788 foo3(42, b);
1789 assert(b == 42);
1790}
1791
1792// move
1793/**
1794Moves `source` into `target`, via a destructive copy when necessary.
1795
1796If `T` is a struct with a destructor or postblit defined, source is reset
1797to its `.init` value after it is moved into target, otherwise it is
1798left unchanged.
1799
1800Preconditions:
1801If source has internal pointers that point to itself and doesn't define
1802opPostMove, it cannot be moved, and will trigger an assertion failure.
1803
1804Params:
1805 source = Data to copy.
1806 target = Where to copy into. The destructor, if any, is invoked before the
1807 copy is performed.
1808*/
1809void move(T)(ref T source, ref T target)
1810{
1811 moveImpl(target, source);
1812}
1813
1814/// For non-struct types, `move` just performs `target = source`:
1815@safe unittest
1816{
1817 Object obj1 = new Object;
1818 Object obj2 = obj1;
1819 Object obj3;
1820
1821 move(obj2, obj3);
1822 assert(obj3 is obj1);
1823 // obj2 unchanged
1824 assert(obj2 is obj1);
1825}
1826
1827///
1828pure nothrow @safe @nogc unittest
1829{
1830 // Structs without destructors are simply copied
1831 struct S1
1832 {
1833 int a = 1;
1834 int b = 2;
1835 }
1836 S1 s11 = { 10, 11 };
1837 S1 s12;
1838
1839 move(s11, s12);
1840
1841 assert(s12 == S1(10, 11));
1842 assert(s11 == s12);
1843
1844 // But structs with destructors or postblits are reset to their .init value
1845 // after copying to the target.
1846 struct S2
1847 {
1848 int a = 1;
1849 int b = 2;
1850
1851 ~this() pure nothrow @safe @nogc { }
1852 }
1853 S2 s21 = { 3, 4 };
1854 S2 s22;
1855
1856 move(s21, s22);
1857
1858 assert(s21 == S2(1, 2));
1859 assert(s22 == S2(3, 4));
1860}
1861
1862@safe unittest
1863{
1864 import core.internal.traits;
1865
1866 assertCTFEable!((){
1867 Object obj1 = new Object;
1868 Object obj2 = obj1;
1869 Object obj3;
1870 move(obj2, obj3);
1871 assert(obj3 is obj1);
1872
1873 static struct S1 { int a = 1, b = 2; }
1874 S1 s11 = { 10, 11 };
1875 S1 s12;
1876 move(s11, s12);
1877 assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11);
1878
1879 static struct S2 { int a = 1; int * b; }
1880 S2 s21 = { 10, null };
1881 s21.b = new int;
1882 S2 s22;
1883 move(s21, s22);
1884 assert(s21 == s22);
1885 });
1886 // Issue 5661 test(1)
1887 static struct S3
1888 {
1889 static struct X { int n = 0; ~this(){n = 0;} }
1890 X x;
1891 }
1892 static assert(hasElaborateDestructor!S3);
1893 S3 s31, s32;
1894 s31.x.n = 1;
1895 move(s31, s32);
1896 assert(s31.x.n == 0);
1897 assert(s32.x.n == 1);
1898
1899 // Issue 5661 test(2)
1900 static struct S4
1901 {
1902 static struct X { int n = 0; this(this){n = 0;} }
1903 X x;
1904 }
1905 static assert(hasElaborateCopyConstructor!S4);
1906 S4 s41, s42;
1907 s41.x.n = 1;
1908 move(s41, s42);
1909 assert(s41.x.n == 0);
1910 assert(s42.x.n == 1);
1911
1912 // Issue 13990 test
1913 class S5;
1914
1915 S5 s51;
1916 S5 s52 = s51;
1917 S5 s53;
1918 move(s52, s53);
1919 assert(s53 is s51);
1920}
1921
1922/// Ditto
1923T move(T)(return scope ref T source)
1924{
1925 return moveImpl(source);
1926}
1927
1928/// Non-copyable structs can still be moved:
1929pure nothrow @safe @nogc unittest
1930{
1931 struct S
1932 {
1933 int a = 1;
1934 @disable this(this);
1935 ~this() pure nothrow @safe @nogc {}
1936 }
1937 S s1;
1938 s1.a = 2;
1939 S s2 = move(s1);
1940 assert(s1.a == 1);
1941 assert(s2.a == 2);
1942}
1943
1944// https://issues.dlang.org/show_bug.cgi?id=20869
1945// `move` should propagate the attributes of `opPostMove`
1946@system unittest
1947{
1948 static struct S
1949 {
1950 void opPostMove(const ref S old) nothrow @system
1951 {
1952 __gshared int i;
1953 new int(i++); // Force @gc impure @system
1954 }
1955 }
1956
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));
1960}
1961
1962private void moveImpl(T)(scope ref T target, return scope ref T source)
1963{
1964 import core.internal.traits : hasElaborateDestructor;
1965
1966 static if (is(T == struct))
1967 {
9c7d5e88 1968 // Unsafe when compiling without -preview=dip1000
5fee5ec3
IB
1969 if ((() @trusted => &source == &target)()) return;
1970 // Destroy target before overwriting it
1971 static if (hasElaborateDestructor!T) target.__xdtor();
1972 }
1973 // move and emplace source into target
1974 moveEmplaceImpl(target, source);
1975}
1976
1977private T moveImpl(T)(return scope ref T source)
1978{
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);
1982
1983 return trustedMoveImpl(source);
1984}
1985
1986private T trustedMoveImpl(T)(return scope ref T source) @trusted
1987{
1988 T result = void;
1989 moveEmplaceImpl(result, source);
1990 return result;
1991}
1992
1993@safe unittest
1994{
1995 import core.internal.traits;
1996
1997 assertCTFEable!((){
1998 Object obj1 = new Object;
1999 Object obj2 = obj1;
2000 Object obj3 = move(obj2);
2001 assert(obj3 is obj1);
2002
2003 static struct S1 { int a = 1, b = 2; }
2004 S1 s11 = { 10, 11 };
2005 S1 s12 = move(s11);
2006 assert(s11.a == 10 && s11.b == 11 && s12.a == 10 && s12.b == 11);
2007
2008 static struct S2 { int a = 1; int * b; }
2009 S2 s21 = { 10, null };
2010 s21.b = new int;
2011 S2 s22 = move(s21);
2012 assert(s21 == s22);
2013 });
2014
2015 // Issue 5661 test(1)
2016 static struct S3
2017 {
2018 static struct X { int n = 0; ~this(){n = 0;} }
2019 X x;
2020 }
2021 static assert(hasElaborateDestructor!S3);
2022 S3 s31;
2023 s31.x.n = 1;
2024 S3 s32 = move(s31);
2025 assert(s31.x.n == 0);
2026 assert(s32.x.n == 1);
2027
2028 // Issue 5661 test(2)
2029 static struct S4
2030 {
2031 static struct X { int n = 0; this(this){n = 0;} }
2032 X x;
2033 }
2034 static assert(hasElaborateCopyConstructor!S4);
2035 S4 s41;
2036 s41.x.n = 1;
2037 S4 s42 = move(s41);
2038 assert(s41.x.n == 0);
2039 assert(s42.x.n == 1);
2040
2041 // Issue 13990 test
2042 class S5;
2043
2044 S5 s51;
2045 S5 s52 = s51;
2046 S5 s53;
2047 s53 = move(s52);
2048 assert(s53 is s51);
2049}
2050
2051@betterC
2052@system unittest
2053{
2054 static struct S { int n = 0; ~this() @system { n = 0; } }
2055 S a, b;
2056 static assert(!__traits(compiles, () @safe { move(a, b); }));
2057 static assert(!__traits(compiles, () @safe { move(a); }));
2058 a.n = 1;
2059 () @trusted { move(a, b); }();
2060 assert(a.n == 0);
2061 a.n = 1;
2062 () @trusted { move(a); }();
2063 assert(a.n == 0);
2064}
2065/+ this can't be tested in druntime, tests are still run in phobos
2066@safe unittest//Issue 6217
2067{
2068 import std.algorithm.iteration : map;
2069 auto x = map!"a"([1,2,3]);
2070 x = move(x);
2071}
2072+/
2073@betterC
2074@safe unittest// Issue 8055
2075{
2076 static struct S
2077 {
2078 int x;
2079 ~this()
2080 {
2081 assert(x == 0);
2082 }
2083 }
2084 S foo(S s)
2085 {
2086 return move(s);
2087 }
2088 S a;
2089 a.x = 0;
2090 auto b = foo(a);
2091 assert(b.x == 0);
2092}
2093
2094@system unittest// Issue 8057
2095{
2096 int n = 10;
2097 struct S
2098 {
2099 int x;
2100 ~this()
2101 {
2102 // Access to enclosing scope
2103 assert(n == 10);
2104 }
2105 }
2106 S foo(S s)
2107 {
2108 // Move nested struct
2109 return move(s);
2110 }
2111 S a;
2112 a.x = 1;
2113 auto b = foo(a);
2114 assert(b.x == 1);
2115
2116 // Regression 8171
2117 static struct Array(T)
2118 {
2119 // nested struct has no member
2120 struct Payload
2121 {
2122 ~this() {}
2123 }
2124 }
2125 Array!int.Payload x = void;
2126 move(x);
2127 move(x, x);
2128}
2129
d7569187
IB
2130private enum bool hasContextPointers(T) = {
2131 static if (__traits(isStaticArray, T))
2132 {
2133 return hasContextPointers!(typeof(T.init[0]));
2134 }
2135 else static if (is(T == struct))
2136 {
2137 import core.internal.traits : anySatisfy;
2138 return __traits(isNested, T) || anySatisfy!(hasContextPointers, typeof(T.tupleof));
2139 }
2140 else return false;
2141} ();
2142
2143@safe @nogc nothrow pure unittest
2144{
2145 static assert(!hasContextPointers!int);
2146 static assert(!hasContextPointers!(void*));
2147
2148 static struct S {}
2149 static assert(!hasContextPointers!S);
2150 static assert(!hasContextPointers!(S[1]));
2151
2152 struct Nested
2153 {
2154 void foo() {}
2155 }
2156
2157 static assert(hasContextPointers!Nested);
2158 static assert(hasContextPointers!(Nested[1]));
2159
2160 static struct OneLevel
2161 {
2162 int before;
2163 Nested n;
2164 int after;
2165 }
2166
2167 static assert(hasContextPointers!OneLevel);
2168 static assert(hasContextPointers!(OneLevel[1]));
2169
2170 static struct TwoLevels
2171 {
2172 int before;
2173 OneLevel o;
2174 int after;
2175 }
2176
2177 static assert(hasContextPointers!TwoLevels);
2178 static assert(hasContextPointers!(TwoLevels[1]));
2179
2180 union U
2181 {
2182 Nested n;
2183 }
2184
2185 // unions can have false positives, so this query ignores them
2186 static assert(!hasContextPointers!U);
2187}
2188
5fee5ec3
IB
2189// target must be first-parameter, because in void-functions DMD + dip1000 allows it to take the place of a return-scope
2190private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source)
2191{
5fee5ec3
IB
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)
2194// {
2195// import std.exception : doesPointTo;
2196// assert(!doesPointTo(source, source) && !hasElaborateMove!T),
2197// "Cannot move object with internal pointer unless `opPostMove` is defined.");
2198// }
2199
d7569187
IB
2200 import core.internal.traits : hasElaborateAssign, isAssignable, hasElaborateMove,
2201 hasElaborateDestructor, hasElaborateCopyConstructor;
5fee5ec3
IB
2202 static if (is(T == struct))
2203 {
fd43568c 2204
9c7d5e88 2205 // Unsafe when compiling without -preview=dip1000
5fee5ec3
IB
2206 assert((() @trusted => &source !is &target)(), "source and target must not be identical");
2207
2208 static if (hasElaborateAssign!T || !isAssignable!T)
fd43568c
IB
2209 {
2210 import core.stdc.string : memcpy;
5fee5ec3 2211 () @trusted { memcpy(&target, &source, T.sizeof); }();
fd43568c 2212 }
5fee5ec3
IB
2213 else
2214 target = source;
2215
2216 static if (hasElaborateMove!T)
2217 __move_post_blt(target, source);
2218
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)
2222 {
d7569187
IB
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
5fee5ec3 2225 static if (__traits(isZeroInit, T))
d7569187
IB
2226 wipe(source);
2227 else
2228 wipe(source, ref () @trusted { return *cast(immutable(T)*) __traits(initSymbol, T).ptr; } ());
2229 }
2230 }
2231 else static if (__traits(isStaticArray, T))
2232 {
2233 static if (T.length)
2234 {
2235 static if (!hasElaborateMove!T &&
2236 !hasElaborateDestructor!T &&
2237 !hasElaborateCopyConstructor!T)
fd43568c 2238 {
d7569187
IB
2239 // Single blit if no special per-instance handling is required
2240 () @trusted
2241 {
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;
2244 } ();
fd43568c 2245 }
5fee5ec3 2246 else
fd43568c 2247 {
d7569187
IB
2248 for (size_t i = 0; i < source.length; ++i)
2249 moveEmplaceImpl(target[i], source[i]);
fd43568c 2250 }
5fee5ec3
IB
2251 }
2252 }
5fee5ec3
IB
2253 else
2254 {
2255 // Primitive data (including pointers and arrays) or class -
2256 // assignment works great
2257 target = source;
2258 }
2259}
2260
2261/**
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.
2265 *
2266 * Params:
2267 * source = value to be moved into target
2268 * target = uninitialized value to be filled by source
2269 */
2270void moveEmplace(T)(ref T source, ref T target) @system
2271{
2272 moveEmplaceImpl(target, source);
2273}
2274
2275///
2276@betterC
2277pure nothrow @nogc @system unittest
2278{
2279 static struct Foo
2280 {
2281 pure nothrow @nogc:
2282 this(int* ptr) { _ptr = ptr; }
2283 ~this() { if (_ptr) ++*_ptr; }
2284 int* _ptr;
2285 }
2286
2287 int val;
2288 Foo foo1 = void; // uninitialized
2289 auto foo2 = Foo(&val); // initialized
2290 assert(foo2._ptr is &val);
2291
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);
2298 assert(val == 0);
2299}
2300
fd43568c
IB
2301@betterC
2302pure nothrow @nogc @system unittest
2303{
2304 static struct Foo
2305 {
2306 pure nothrow @nogc:
2307 this(int* ptr) { _ptr = ptr; }
2308 ~this() { if (_ptr) ++*_ptr; }
2309 int* _ptr;
2310 }
2311
2312 int val;
2313 {
2314 Foo[1] foo1 = void; // uninitialized
2315 Foo[1] foo2 = [Foo(&val)];// initialized
2316 assert(foo2[0]._ptr is &val);
2317
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);
2324 assert(val == 0);
2325 }
2326 assert(val == 1);
2327}
2328
e9251fea 2329// https://issues.dlang.org/show_bug.cgi?id=18913
5fee5ec3
IB
2330@safe unittest
2331{
2332 static struct NoCopy
2333 {
2334 int payload;
2335 ~this() { }
2336 @disable this(this);
2337 }
2338
2339 static void f(NoCopy[2]) { }
2340
2341 NoCopy[2] ncarray = [ NoCopy(1), NoCopy(2) ];
2342
2343 static assert(!__traits(compiles, f(ncarray)));
2344 f(move(ncarray));
2345}
9c7d5e88 2346
d7569187
IB
2347//debug = PRINTF;
2348
2349debug(PRINTF)
2350{
2351 import core.stdc.stdio;
2352}
2353
fd43568c
IB
2354/// Implementation of `_d_delstruct` and `_d_delstructTrace`
2355template _d_delstructImpl(T)
9c7d5e88 2356{
fd43568c 2357 private void _d_delstructImpure(ref T p)
9c7d5e88
IB
2358 {
2359 debug(PRINTF) printf("_d_delstruct(%p)\n", p);
2360
2361 import core.memory : GC;
2362
2363 destroy(*p);
2364 GC.free(p);
2365 p = null;
2366 }
fd43568c
IB
2367
2368 /**
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.
2372 *
2373 * Params:
2374 * p = pointer to the value to be deleted
2375 *
2376 * Bugs:
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
2381 * expectations.
2382 */
2383 void _d_delstruct(ref T p) @trusted @nogc pure nothrow
2384 {
2385 if (p)
2386 {
2387 alias Type = void function(ref T P) @nogc pure nothrow;
2388 (cast(Type) &_d_delstructImpure)(p);
2389 }
2390 }
2391
8da8c7d3
IB
2392 version (D_ProfileGC)
2393 {
2394 import core.internal.array.utils : _d_HookTraceImpl;
fd43568c 2395
8da8c7d3 2396 private enum errorMessage = "Cannot delete struct if compiling without support for runtime type information!";
fd43568c 2397
8da8c7d3
IB
2398 /**
2399 * TraceGC wrapper around $(REF _d_delstruct, core,lifetime,_d_delstructImpl).
2400 *
2401 * Bugs:
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
2406 * expectations.
2407 */
2408 alias _d_delstructTrace = _d_HookTraceImpl!(T, _d_delstruct, errorMessage);
2409 }
9c7d5e88
IB
2410}
2411
fd43568c 2412@system pure nothrow unittest
9c7d5e88
IB
2413{
2414 int dtors = 0;
b3f58f87 2415 struct S { ~this() nothrow { ++dtors; } }
9c7d5e88
IB
2416
2417 S *s = new S();
fd43568c 2418 _d_delstructImpl!(typeof(s))._d_delstruct(s);
9c7d5e88
IB
2419
2420 assert(s == null);
2421 assert(dtors == 1);
2422}
2423
fd43568c 2424@system pure unittest
9c7d5e88
IB
2425{
2426 int innerDtors = 0;
2427 int outerDtors = 0;
2428
2429 struct Inner { ~this() { ++innerDtors; } }
2430 struct Outer
2431 {
2432 Inner *i1;
2433 Inner *i2;
2434
2435 this(int x)
2436 {
2437 i1 = new Inner();
2438 i2 = new Inner();
2439 }
2440
2441 ~this()
2442 {
2443 ++outerDtors;
2444
fd43568c 2445 _d_delstructImpl!(typeof(i1))._d_delstruct(i1);
9c7d5e88
IB
2446 assert(i1 == null);
2447
fd43568c 2448 _d_delstructImpl!(typeof(i2))._d_delstruct(i2);
9c7d5e88
IB
2449 assert(i2 == null);
2450 }
2451 }
2452
2453 Outer *o = new Outer(0);
fd43568c 2454 _d_delstructImpl!(typeof(o))._d_delstruct(o);
9c7d5e88
IB
2455
2456 assert(o == null);
2457 assert(innerDtors == 2);
2458 assert(outerDtors == 1);
2459}
d7569187 2460
e9251fea 2461// https://issues.dlang.org/show_bug.cgi?id=25552
d7569187
IB
2462pure nothrow @system unittest
2463{
2464 int i;
2465 struct Nested
2466 {
2467 pure nothrow @nogc:
2468 char[1] arr; // char.init is not 0
2469 ~this() { ++i; }
2470 }
2471
2472 {
2473 Nested[1] dst = void;
2474 Nested[1] src = [Nested(['a'])];
2475
2476 moveEmplace(src, dst);
2477 assert(i == 0);
2478 assert(dst[0].arr == ['a']);
2479 assert(src[0].arr == [char.init]);
2480 assert(dst[0].tupleof[$-1] is src[0].tupleof[$-1]);
2481 }
2482 assert(i == 2);
2483}
2484
e9251fea 2485// https://issues.dlang.org/show_bug.cgi?id=25552
d7569187
IB
2486@safe unittest
2487{
2488 int i;
2489 struct Nested
2490 {
2491 ~this() { ++i; }
2492 }
2493
2494 static struct NotNested
2495 {
2496 Nested n;
2497 }
2498
2499 static struct Deep
2500 {
2501 NotNested nn;
2502 }
2503
2504 static struct Deeper
2505 {
2506 NotNested[1] nn;
2507 }
2508
2509 static assert(__traits(isZeroInit, Nested));
2510 static assert(__traits(isZeroInit, NotNested));
2511 static assert(__traits(isZeroInit, Deep));
2512 static assert(__traits(isZeroInit, Deeper));
2513
2514 {
2515 auto a = NotNested(Nested());
2516 assert(a.n.tupleof[$-1]);
2517 auto b = move(a);
2518 assert(b.n.tupleof[$-1]);
2519 assert(a.n.tupleof[$-1] is b.n.tupleof[$-1]);
2520
2521 auto c = Deep(NotNested(Nested()));
2522 auto d = move(c);
2523 assert(d.nn.n.tupleof[$-1]);
2524 assert(c.nn.n.tupleof[$-1] is d.nn.n.tupleof[$-1]);
2525
2526 auto e = Deeper([NotNested(Nested())]);
2527 auto f = move(e);
2528 assert(f.nn[0].n.tupleof[$-1]);
2529 assert(e.nn[0].n.tupleof[$-1] is f.nn[0].n.tupleof[$-1]);
2530 }
2531 assert(i == 6);
2532}
2533
e9251fea 2534// https://issues.dlang.org/show_bug.cgi?id=25552
d7569187
IB
2535@safe unittest
2536{
2537 int i;
2538 struct Nested
2539 {
2540 align(32) // better still find context pointer correctly!
2541 int[3] stuff = [0, 1, 2];
2542 ~this() { ++i; }
2543 }
2544
2545 static struct NoAssign
2546 {
2547 int value;
2548 @disable void opAssign(typeof(this));
2549 }
2550
2551 static struct NotNested
2552 {
2553 int before = 42;
2554 align(Nested.alignof * 4) // better still find context pointer correctly!
2555 Nested n;
2556 auto after = NoAssign(43);
2557 }
2558
2559 static struct Deep
2560 {
2561 NotNested nn;
2562 }
2563
2564 static struct Deeper
2565 {
2566 NotNested[1] nn;
2567 }
2568
2569 static assert(!__traits(isZeroInit, Nested));
2570 static assert(!__traits(isZeroInit, NotNested));
2571 static assert(!__traits(isZeroInit, Deep));
2572 static assert(!__traits(isZeroInit, Deeper));
2573
2574 {
2575 auto a = NotNested(1, Nested([3, 4, 5]), NoAssign(2));
2576 auto b = move(a);
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));
2582
2583 auto c = Deep(NotNested(1, Nested([3, 4, 5]), NoAssign(2)));
2584 auto d = move(c);
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));
2590
2591 auto e = Deeper([NotNested(1, Nested([3, 4, 5]), NoAssign(2))]);
2592 auto f = move(e);
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));
2598 }
2599 assert(i == 6);
2600}
2601
2602// wipes source after moving
2603pragma(inline, true)
2604private void wipe(T, Init...)(return scope ref T source, ref const scope Init initializer) @trusted
2605if (!Init.length ||
2606 ((Init.length == 1) && (is(immutable T == immutable Init[0]))))
2607{
2608 static if (__traits(isStaticArray, T) && hasContextPointers!T)
2609 {
2610 for (auto i = 0; i < T.length; i++)
2611 static if (Init.length)
2612 wipe(source[i], initializer[0][i]);
2613 else
2614 wipe(source[i]);
2615 }
2616 else static if (is(T == struct) && hasContextPointers!T)
2617 {
2618 import core.internal.traits : anySatisfy;
2619 static if (anySatisfy!(hasContextPointers, typeof(T.tupleof)))
2620 {
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]);
2624 else
2625 wipe(source.tupleof[i]);
2626 }
2627 else
2628 {
2629 static if (__traits(isNested, T))
2630 enum sz = T.tupleof[$-1].offsetof;
2631 else
2632 enum sz = T.sizeof;
2633
2634 static if (Init.length)
2635 *cast(ubyte[sz]*) &source = *cast(ubyte[sz]*) &initializer[0];
2636 else
2637 *cast(ubyte[sz]*) &source = 0;
2638 }
2639 }
2640 else
2641 {
2642 import core.internal.traits : hasElaborateAssign, isAssignable;
2643 static if (Init.length)
2644 {
2645 static if (hasElaborateAssign!T || !isAssignable!T)
2646 *cast(ubyte[T.sizeof]*) &source = *cast(ubyte[T.sizeof]*) &initializer[0];
2647 else
2648 source = *cast(T*) &initializer[0];
2649 }
2650 else
2651 {
2652 *cast(ubyte[T.sizeof]*) &source = 0;
2653 }
2654 }
2655}
2656
2657/**
ec486b73
IB
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.
2660 *
2661 * Note:
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.
2665 *
d7569187 2666 * Returns:
ec486b73 2667 * allocated instance of type `T`
d7569187 2668 */
ec486b73
IB
2669T _d_newThrowable(T)() @trusted
2670 if (is(T : Throwable) && __traits(getLinkage, T) == "D")
d7569187
IB
2671{
2672 debug(PRINTF) printf("_d_newThrowable(%s)\n", cast(char*) T.stringof);
2673
6384eff5 2674 import core.memory : pureMalloc;
d7569187 2675 auto init = __traits(initSymbol, T);
6384eff5 2676 void* p = pureMalloc(init.length);
d7569187
IB
2677 if (!p)
2678 {
2679 import core.exception : onOutOfMemoryError;
2680 onOutOfMemoryError();
2681 }
2682
2683 debug(PRINTF) printf(" p = %p\n", p);
2684
2685 // initialize it
2686 p[0 .. init.length] = init[];
2687
2688 import core.internal.traits : hasIndirections;
2689 if (hasIndirections!T)
2690 {
2691 // Inform the GC about the pointers in the object instance
2692 import core.memory : GC;
2693 GC.addRange(p, init.length);
2694 }
2695
2696 debug(PRINTF) printf("initialization done\n");
2697
2698 (cast(Throwable) p).refcount() = 1;
2699
ec486b73 2700 return cast(T) p;
d7569187
IB
2701}
2702
2703@system unittest
2704{
2705 class E : Exception
2706 {
ec486b73 2707 this(string msg = "", Throwable nextInChain = null)
d7569187
IB
2708 {
2709 super(msg, nextInChain);
d7569187
IB
2710 }
2711 }
2712
ec486b73
IB
2713 Throwable exc = _d_newThrowable!Exception();
2714 Throwable e = _d_newThrowable!E();
d7569187 2715
ec486b73 2716 assert(exc.refcount() == 1);
d7569187 2717 assert(e.refcount() == 1);
d7569187 2718}
8da8c7d3
IB
2719
2720/**
2721 * Create a new class instance.
2722 * Allocates memory and sets fields to their initial value, but does not call a
2723 * constructor.
2724 * ---
2725 * new C() // _d_newclass!(C)()
2726 * ---
2727 * Returns: newly created object
2728 */
2729T _d_newclassT(T)() @trusted
2730if (is(T == class))
2731{
2732 import core.internal.traits : hasIndirections;
2733 import core.exception : onOutOfMemoryError;
e773c6c7
IB
2734 import core.memory : pureMalloc;
2735 import core.memory : GC;
8da8c7d3
IB
2736
2737 alias BlkAttr = GC.BlkAttr;
2738
2739 auto init = __traits(initSymbol, T);
2740 void* p;
2741
2742 static if (__traits(getLinkage, T) == "Windows")
2743 {
2744 p = pureMalloc(init.length);
2745 if (!p)
2746 onOutOfMemoryError();
2747 }
2748 else
2749 {
2750 BlkAttr attr = BlkAttr.NONE;
2751
2752 /* `extern(C++)`` classes don't have a classinfo pointer in their vtable,
2753 * so the GC can't finalize them.
2754 */
2755 static if (__traits(hasMember, T, "__dtor") && __traits(getLinkage, T) != "C++")
2756 attr |= BlkAttr.FINALIZE;
2757 static if (!hasIndirections!T)
2758 attr |= BlkAttr.NO_SCAN;
2759
2760 p = GC.malloc(init.length, attr, typeid(T));
2761 debug(PRINTF) printf(" p = %p\n", p);
2762 }
2763
2764 debug(PRINTF)
2765 {
2766 printf("p = %p\n", p);
2767 printf("init.ptr = %p, len = %llu\n", init.ptr, cast(ulong)init.length);
2768 printf("vptr = %p\n", *cast(void**) init);
2769 printf("vtbl[0] = %p\n", (*cast(void***) init)[0]);
2770 printf("vtbl[1] = %p\n", (*cast(void***) init)[1]);
2771 printf("init[0] = %x\n", (cast(uint*) init)[0]);
2772 printf("init[1] = %x\n", (cast(uint*) init)[1]);
2773 printf("init[2] = %x\n", (cast(uint*) init)[2]);
2774 printf("init[3] = %x\n", (cast(uint*) init)[3]);
2775 printf("init[4] = %x\n", (cast(uint*) init)[4]);
2776 }
2777
2778 // initialize it
2779 p[0 .. init.length] = init[];
2780
2781 debug(PRINTF) printf("initialization done\n");
2782 return cast(T) p;
2783}
2784
0cafc3b6
IB
2785/**
2786 * TraceGC wrapper around $(REF _d_newclassT, core,lifetime).
2787 */
2788T _d_newclassTTrace(T)(string file, int line, string funcname) @trusted
2789{
2790 version (D_TypeInfo)
2791 {
2792 import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure;
2793 mixin(TraceHook!(T.stringof, "_d_newclassT"));
2794
2795 return _d_newclassT!T();
2796 }
2797 else
2798 assert(0, "Cannot create new class if compiling without support for runtime type information!");
2799}
2800
2801/**
2802 * Allocate an initialized non-array item.
2803 *
2804 * This is an optimization to avoid things needed for arrays like the __arrayPad(size).
2805 * Used to allocate struct instances on the heap.
2806 *
2807 * ---
2808 * struct Sz {int x = 0;}
2809 * struct Si {int x = 3;}
2810 *
2811 * void main()
2812 * {
2813 * new Sz(); // uses zero-initialization
2814 * new Si(); // uses Si.init
2815 * }
2816 * ---
2817 *
2818 * Returns:
2819 * newly allocated item
2820 */
2821T* _d_newitemT(T)() @trusted
2822{
2823 import core.internal.lifetime : emplaceInitializer;
e773c6c7 2824 import core.internal.traits : hasIndirections;
0cafc3b6
IB
2825 import core.memory : GC;
2826
2827 auto flags = !hasIndirections!T ? GC.BlkAttr.NO_SCAN : GC.BlkAttr.NONE;
e773c6c7 2828 immutable tiSize = TypeInfoSize!T;
0cafc3b6
IB
2829 immutable itemSize = T.sizeof;
2830 immutable totalSize = itemSize + tiSize;
2831 if (tiSize)
2832 flags |= GC.BlkAttr.STRUCTFINAL | GC.BlkAttr.FINALIZE;
2833
2834 auto blkInfo = GC.qalloc(totalSize, flags, null);
2835 auto p = blkInfo.base;
2836
2837 if (tiSize)
2838 {
2839 // The GC might not have cleared the padding area in the block.
2840 *cast(TypeInfo*) (p + (itemSize & ~(size_t.sizeof - 1))) = null;
2841 *cast(TypeInfo*) (p + blkInfo.size - tiSize) = cast() typeid(T);
2842 }
2843
2844 emplaceInitializer(*(cast(T*) p));
2845
2846 return cast(T*) p;
2847}
2848
8da8c7d3
IB
2849// Test allocation
2850@safe unittest
2851{
2852 class C { }
2853 C c = _d_newclassT!C();
2854
2855 assert(c !is null);
2856}
2857
2858// Test initializers
2859@safe unittest
2860{
2861 {
2862 class C { int x, y; }
2863 C c = _d_newclassT!C();
2864
2865 assert(c.x == 0);
2866 assert(c.y == 0);
2867 }
2868 {
2869 class C { int x = 2, y = 3; }
2870 C c = _d_newclassT!C();
2871
2872 assert(c.x == 2);
2873 assert(c.y == 3);
2874 }
2875}
2876
0cafc3b6
IB
2877// Test allocation
2878@safe unittest
2879{
2880 struct S { }
2881 S* s = _d_newitemT!S();
2882
2883 assert(s !is null);
2884}
2885
2886// Test initializers
2887@safe unittest
8da8c7d3 2888{
8da8c7d3 2889 {
0cafc3b6
IB
2890 // zero-initialization
2891 struct S { int x, y; }
2892 S* s = _d_newitemT!S();
8da8c7d3 2893
0cafc3b6
IB
2894 assert(s.x == 0);
2895 assert(s.y == 0);
2896 }
2897 {
2898 // S.init
2899 struct S { int x = 2, y = 3; }
2900 S* s = _d_newitemT!S();
2901
2902 assert(s.x == 2);
2903 assert(s.y == 3);
2904 }
2905}
2906
2907// Test GC attributes
2908version (CoreUnittest)
2909{
2910 struct S1
2911 {
2912 int x = 5;
2913 }
2914 struct S2
2915 {
2916 int x;
2917 this(int x) { this.x = x; }
2918 }
2919 struct S3
2920 {
2921 int[4] x;
2922 this(int x) { this.x[] = x; }
2923 }
2924 struct S4
2925 {
2926 int *x;
2927 }
2928
2929}
2930@system unittest
2931{
2932 import core.memory : GC;
2933
2934 auto s1 = new S1;
2935 assert(s1.x == 5);
2936 assert(GC.getAttr(s1) == GC.BlkAttr.NO_SCAN);
2937
2938 auto s2 = new S2(3);
2939 assert(s2.x == 3);
2940 assert(GC.getAttr(s2) == GC.BlkAttr.NO_SCAN);
2941
2942 auto s3 = new S3(1);
2943 assert(s3.x == [1, 1, 1, 1]);
2944 assert(GC.getAttr(s3) == GC.BlkAttr.NO_SCAN);
2945 debug(SENTINEL) {} else
2946 assert(GC.sizeOf(s3) == 16);
2947
2948 auto s4 = new S4;
2949 assert(s4.x == null);
2950 assert(GC.getAttr(s4) == 0);
2951}
2952
2953// Test struct finalizers exception handling
2954debug(SENTINEL) {} else
2955@system unittest
2956{
2957 import core.memory : GC;
2958
2959 bool test(E)()
2960 {
2961 import core.exception;
2962 static struct S1
2963 {
2964 E exc;
2965 ~this() { throw exc; }
2966 }
2967
2968 bool caught = false;
2969 S1* s = new S1(new E("test onFinalizeError"));
2970 try
2971 {
2972 GC.runFinalizers((cast(char*)(typeid(S1).xdtor))[0 .. 1]);
2973 }
2974 catch (FinalizeError err)
2975 {
2976 caught = true;
2977 }
2978 catch (E)
2979 {
2980 }
2981 GC.free(s);
2982 return caught;
2983 }
2984
2985 assert(test!Exception);
2986 import core.exception : InvalidMemoryOperationError;
2987 assert(!test!InvalidMemoryOperationError);
2988}
2989
2990version (D_ProfileGC)
2991{
2992 /**
2993 * TraceGC wrapper around $(REF _d_newitemT, core,lifetime).
2994 */
2995 T* _d_newitemTTrace(T)(string file, int line, string funcname) @trusted
2996 {
2997 version (D_TypeInfo)
2998 {
2999 import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure;
3000 mixin(TraceHook!(T.stringof, "_d_newitemT"));
3001
3002 return _d_newitemT!T();
3003 }
3004 else
3005 assert(0, "Cannot create new `struct` if compiling without support for runtime type information!");
8da8c7d3 3006 }
8da8c7d3 3007}
e773c6c7
IB
3008
3009template TypeInfoSize(T)
3010{
3011 import core.internal.traits : hasElaborateDestructor;
51c4eb28 3012 enum TypeInfoSize = (is (T == struct) && hasElaborateDestructor!T) ? size_t.sizeof : 0;
e773c6c7 3013}