1 module core.lifetime; 2 3 import core.internal.attributes : betterC; 4 5 // emplace 6 /** 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 11 as `chunk`). 12 */ 13 T* 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 /** 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 55 `T` is `@safe`. 56 Returns: A pointer to the newly constructed object (which is the same 57 as `chunk`). 58 */ 59 T* 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 /** 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. 93 Note: 94 This function is `@safe` if the corresponding constructor of `T` is `@safe`. 95 Returns: The newly constructed object. 96 */ 97 T 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 106 const initializer = __traits(initSymbol, T); 107 (() @trusted { (cast(void*) chunk)[0 .. initializer.length] = initializer[]; })(); 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 /** 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. 192 Preconditions: 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))). 196 Note: 197 This function can be `@trusted` if the corresponding constructor of `T` is `@safe`. 198 Returns: The newly constructed object. 199 */ 200 T emplace(T, Args...)(void[] chunk, auto ref Args args) 201 if (is(T == class)) 202 { 203 enum classSize = __traits(classInstanceSize, T); 204 assert(chunk.length >= classSize, "chunk size too small."); 205 206 enum alignment = __traits(classInstanceAlignment, T); 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 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 243 align(__traits(classInstanceAlignment, C)) byte[__traits(classInstanceSize, C)] buffer; 244 C c = emplace!C(buffer[], 42); 245 assert(c.virtualGetI() == 42); 246 } 247 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; 289 align(__traits(classInstanceAlignment, __conv_EmplaceTestClass)) 290 ubyte[__traits(classInstanceSize, __conv_EmplaceTestClass)] buf; 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 /** 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. 308 Preconditions: 309 `chunk` must be at least as large 310 as `T` needs and should have an alignment multiple of `T`'s 311 alignment. 312 Note: 313 This function can be `@trusted` if the corresponding constructor of 314 `T` is `@safe`. 315 Returns: A pointer to the newly constructed object. 316 */ 317 T* 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 367 @system unittest // https://issues.dlang.org/show_bug.cgi?id=15772 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 810 version (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 1121 pure 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 1133 pure 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 1198 static align(__traits(classInstanceAlignment, A)) byte[__traits(classInstanceSize, A)] sbuf; 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 */ 1245 void 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 { 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)) 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 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 1391 version (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 1413 version (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 /** 1551 Forwards function arguments while keeping `out`, `ref`, and `lazy` on 1552 the parameters. 1553 1554 Params: 1555 args = a parameter list or an $(REF AliasSeq,std,meta). 1556 Returns: 1557 An `AliasSeq` of `args` with `out`, `ref`, and `lazy` saved. 1558 */ 1559 template forward(args...) 1560 { 1561 import core.internal.traits : AliasSeq; 1562 1563 template fwd(alias arg) 1564 { 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 1573 @property auto fwd() 1574 { 1575 version (DigitalMars) { /* @@BUG 23890@@ */ } else pragma(inline, true); 1576 return move(arg); 1577 } 1578 } 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]; 1585 else 1586 alias forward = Result; 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 /** 1794 Moves `source` into `target`, via a destructive copy when necessary. 1795 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 1798 left unchanged. 1799 1800 Preconditions: 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. 1803 1804 Params: 1805 source = Data to copy. 1806 target = Where to copy into. The destructor, if any, is invoked before the 1807 copy is performed. 1808 */ 1809 void 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 /// 1828 pure 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 1923 T move(T)(return scope ref T source) 1924 { 1925 return moveImpl(source); 1926 } 1927 1928 /// Non-copyable structs can still be moved: 1929 pure 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 1962 private 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 { 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(); 1972 } 1973 // move and emplace source into target 1974 moveEmplaceImpl(target, source); 1975 } 1976 1977 private 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 1986 private 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 2130 private 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 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) 2191 { 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 2200 import core.internal.traits : hasElaborateAssign, isAssignable, hasElaborateMove, 2201 hasElaborateDestructor, hasElaborateCopyConstructor; 2202 static if (is(T == struct)) 2203 { 2204 2205 // Unsafe when compiling without -preview=dip1000 2206 assert((() @trusted => &source !is &target)(), "source and target must not be identical"); 2207 2208 static if (hasElaborateAssign!T || !isAssignable!T) 2209 { 2210 import core.stdc.string : memcpy; 2211 () @trusted { memcpy(&target, &source, T.sizeof); }(); 2212 } 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 { 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)) 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) 2238 { 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 } (); 2245 } 2246 else 2247 { 2248 for (size_t i = 0; i < source.length; ++i) 2249 moveEmplaceImpl(target[i], source[i]); 2250 } 2251 } 2252 } 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 */ 2270 void moveEmplace(T)(ref T source, ref T target) @system 2271 { 2272 moveEmplaceImpl(target, source); 2273 } 2274 2275 /// 2276 @betterC 2277 pure 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 2301 @betterC 2302 pure 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 2329 // https://issues.dlang.org/show_bug.cgi?id=18913 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 } 2346 2347 //debug = PRINTF; 2348 2349 debug(PRINTF) 2350 { 2351 import core.stdc.stdio; 2352 } 2353 2354 /// Implementation of `_d_delstruct` and `_d_delstructTrace` 2355 template _d_delstructImpl(T) 2356 { 2357 private void _d_delstructImpure(ref T p) 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 } 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 2392 version (D_ProfileGC) 2393 { 2394 import core.internal.array.utils : _d_HookTraceImpl; 2395 2396 private enum errorMessage = "Cannot delete struct if compiling without support for runtime type information!"; 2397 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 } 2410 } 2411 2412 @system pure nothrow unittest 2413 { 2414 int dtors = 0; 2415 struct S { ~this() nothrow { ++dtors; } } 2416 2417 S *s = new S(); 2418 _d_delstructImpl!(typeof(s))._d_delstruct(s); 2419 2420 assert(s == null); 2421 assert(dtors == 1); 2422 } 2423 2424 @system pure unittest 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 2445 _d_delstructImpl!(typeof(i1))._d_delstruct(i1); 2446 assert(i1 == null); 2447 2448 _d_delstructImpl!(typeof(i2))._d_delstruct(i2); 2449 assert(i2 == null); 2450 } 2451 } 2452 2453 Outer *o = new Outer(0); 2454 _d_delstructImpl!(typeof(o))._d_delstruct(o); 2455 2456 assert(o == null); 2457 assert(innerDtors == 2); 2458 assert(outerDtors == 1); 2459 } 2460 2461 // https://issues.dlang.org/show_bug.cgi?id=25552 2462 pure 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 2485 // https://issues.dlang.org/show_bug.cgi?id=25552 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 2534 // https://issues.dlang.org/show_bug.cgi?id=25552 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 2603 pragma(inline, true) 2604 private void wipe(T, Init...)(return scope ref T source, ref const scope Init initializer) @trusted 2605 if (!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 /** 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 * 2666 * Returns: 2667 * allocated instance of type `T` 2668 */ 2669 T _d_newThrowable(T)() @trusted 2670 if (is(T : Throwable) && __traits(getLinkage, T) == "D") 2671 { 2672 debug(PRINTF) printf("_d_newThrowable(%s)\n", cast(char*) T.stringof); 2673 2674 import core.memory : pureMalloc; 2675 auto init = __traits(initSymbol, T); 2676 void* p = pureMalloc(init.length); 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 2700 return cast(T) p; 2701 } 2702 2703 @system unittest 2704 { 2705 class E : Exception 2706 { 2707 this(string msg = "", Throwable nextInChain = null) 2708 { 2709 super(msg, nextInChain); 2710 } 2711 } 2712 2713 Throwable exc = _d_newThrowable!Exception(); 2714 Throwable e = _d_newThrowable!E(); 2715 2716 assert(exc.refcount() == 1); 2717 assert(e.refcount() == 1); 2718 } 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 */ 2729 T _d_newclassT(T)() @trusted 2730 if (is(T == class)) 2731 { 2732 import core.internal.traits : hasIndirections; 2733 import core.exception : onOutOfMemoryError; 2734 import core.memory : pureMalloc; 2735 import core.memory : GC; 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 2785 /** 2786 * TraceGC wrapper around $(REF _d_newclassT, core,lifetime). 2787 */ 2788 T _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 */ 2821 T* _d_newitemT(T)() @trusted 2822 { 2823 import core.internal.lifetime : emplaceInitializer; 2824 import core.internal.traits : hasIndirections; 2825 import core.memory : GC; 2826 2827 auto flags = !hasIndirections!T ? GC.BlkAttr.NO_SCAN : GC.BlkAttr.NONE; 2828 immutable tiSize = TypeInfoSize!T; 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 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 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 2888 { 2889 { 2890 // zero-initialization 2891 struct S { int x, y; } 2892 S* s = _d_newitemT!S(); 2893 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 2908 version (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 2954 debug(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 2990 version (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!"); 3006 } 3007 } 3008 3009 template TypeInfoSize(T) 3010 { 3011 import core.internal.traits : hasElaborateDestructor; 3012 enum TypeInfoSize = (is (T == struct) && hasElaborateDestructor!T) ? size_t.sizeof : 0; 3013 }