1 /** 2 * Forms the symbols available to all D programs. Includes Object, which is 3 * the root of the class object hierarchy. This module is implicitly 4 * imported. 5 * 6 * Copyright: Copyright Digital Mars 2000 - 2011. 7 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 8 * Authors: Walter Bright, Sean Kelly 9 */ 10 11 module object; 12 13 /// Pretend we use CRuntime_Glibc and Posix 14 15 version(WASI) {} else static assert(0, "WASI interface required. You must compile with wasmXX-unknown-wasi."); 16 17 // NOTE: For some reason, this declaration method doesn't work 18 // in this particular file (and this file only). It must 19 // be a DMD thing. 20 //alias typeof(int.sizeof) size_t; 21 //alias typeof(cast(void*)0 - cast(void*)0) ptrdiff_t; 22 23 version (D_LP64) 24 { 25 alias size_t = ulong; 26 alias ptrdiff_t = long; 27 } 28 else 29 { 30 alias size_t = uint; 31 alias ptrdiff_t = int; 32 } 33 34 alias sizediff_t = ptrdiff_t; //For backwards compatibility only. 35 36 alias noreturn = typeof(*null); 37 38 alias hash_t = size_t; //For backwards compatibility only. 39 alias equals_t = bool; //For backwards compatibility only. 40 alias time_t = ulong; 41 alias string = immutable(char)[]; 42 alias wstring = immutable(wchar)[]; 43 alias dstring = immutable(dchar)[]; 44 45 version (LDC) 46 { 47 // Layout of this struct must match __gnuc_va_list for C ABI compatibility. 48 // Defined here for LDC as it is referenced from implicitly generated code 49 // for D-style variadics, etc., and we do not require people to manually 50 // import core.vararg like DMD does. 51 version (X86_64) 52 { 53 struct __va_list_tag 54 { 55 uint offset_regs = 6 * 8; 56 uint offset_fpregs = 6 * 8 + 8 * 16; 57 void* stack_args; 58 void* reg_args; 59 } 60 } 61 else version (AArch64) 62 { 63 version (iOS) {} 64 else version (TVOS) {} 65 else 66 { 67 static import ldc.internal.vararg; 68 alias __va_list = ldc.internal.vararg.std.__va_list; 69 } 70 } 71 else version (ARM) 72 { 73 // Darwin does not use __va_list 74 version (iOS) {} 75 else version (WatchOS) {} 76 else 77 { 78 static import ldc.internal.vararg; 79 alias __va_list = ldc.internal.vararg.std.__va_list; 80 } 81 } 82 } 83 84 version (D_ObjectiveC) public import core.attribute : selector; 85 86 int __cmp(T)(scope const T[] lhs, scope const T[] rhs) @trusted 87 if (__traits(isScalar, T)) 88 { 89 // Compute U as the implementation type for T 90 static if (is(T == ubyte) || is(T == void) || is(T == bool)) 91 alias U = char; 92 else static if (is(T == wchar)) 93 alias U = ushort; 94 else static if (is(T == dchar)) 95 alias U = uint; 96 else static if (is(T == ifloat)) 97 alias U = float; 98 else static if (is(T == idouble)) 99 alias U = double; 100 else static if (is(T == ireal)) 101 alias U = real; 102 else 103 alias U = T; 104 105 static if (is(U == char)) 106 { 107 import core.internal.string : dstrcmp; 108 return dstrcmp(cast(char[]) lhs, cast(char[]) rhs); 109 } 110 else static if (!is(U == T)) 111 { 112 // Reuse another implementation 113 return __cmp(cast(U[]) lhs, cast(U[]) rhs); 114 } 115 else 116 { 117 version (BigEndian) 118 static if (__traits(isUnsigned, T) ? !is(T == __vector) : is(T : P*, P)) 119 { 120 if (!__ctfe) 121 { 122 import core.stdc.string : memcmp; 123 int c = memcmp(lhs.ptr, rhs.ptr, (lhs.length <= rhs.length ? lhs.length : rhs.length) * T.sizeof); 124 if (c) 125 return c; 126 static if (size_t.sizeof <= uint.sizeof && T.sizeof >= 2) 127 return cast(int) lhs.length - cast(int) rhs.length; 128 else 129 return int(lhs.length > rhs.length) - int(lhs.length < rhs.length); 130 } 131 } 132 133 immutable len = lhs.length <= rhs.length ? lhs.length : rhs.length; 134 foreach (const u; 0 .. len) 135 { 136 static if (__traits(isFloating, T)) 137 { 138 immutable a = lhs.ptr[u], b = rhs.ptr[u]; 139 static if (is(T == cfloat) || is(T == cdouble) 140 || is(T == creal)) 141 { 142 // Use rt.cmath2._Ccmp instead ? 143 auto r = (a.re > b.re) - (a.re < b.re); 144 if (!r) r = (a.im > b.im) - (a.im < b.im); 145 } 146 else 147 { 148 const r = (a > b) - (a < b); 149 } 150 if (r) return r; 151 } 152 else if (lhs.ptr[u] != rhs.ptr[u]) 153 return lhs.ptr[u] < rhs.ptr[u] ? -1 : 1; 154 } 155 return lhs.length < rhs.length ? -1 : (lhs.length > rhs.length); 156 } 157 } 158 159 // Compare class and interface objects for ordering. 160 private int __cmp(Obj)(Obj lhs, Obj rhs) 161 if (is(Obj : Object)) 162 { 163 if (lhs is rhs) 164 return 0; 165 // Regard null references as always being "less than" 166 if (!lhs) 167 return -1; 168 if (!rhs) 169 return 1; 170 return lhs.opCmp(rhs); 171 } 172 173 174 // This function is called by the compiler when dealing with array 175 // comparisons in the semantic analysis phase of CmpExp. The ordering 176 // comparison is lowered to a call to this template. 177 int __cmp(T1, T2)(T1[] s1, T2[] s2) 178 if (!__traits(isScalar, T1) && !__traits(isScalar, T2)) 179 { 180 import core.internal.traits : Unqual; 181 alias U1 = Unqual!T1; 182 alias U2 = Unqual!T2; 183 184 static if (is(U1 == void) && is(U2 == void)) 185 static @trusted ref inout(ubyte) at(inout(void)[] r, size_t i) { return (cast(inout(ubyte)*) r.ptr)[i]; } 186 else 187 static @trusted ref R at(R)(R[] r, size_t i) { return r.ptr[i]; } 188 189 // All unsigned byte-wide types = > dstrcmp 190 immutable len = s1.length <= s2.length ? s1.length : s2.length; 191 192 foreach (const u; 0 .. len) 193 { 194 static if (__traits(compiles, __cmp(at(s1, u), at(s2, u)))) 195 { 196 auto c = __cmp(at(s1, u), at(s2, u)); 197 if (c != 0) 198 return c; 199 } 200 else static if (__traits(compiles, at(s1, u).opCmp(at(s2, u)))) 201 { 202 auto c = at(s1, u).opCmp(at(s2, u)); 203 if (c != 0) 204 return c; 205 } 206 else static if (__traits(compiles, at(s1, u) < at(s2, u))) 207 { 208 if (at(s1, u) != at(s2, u)) 209 return at(s1, u) < at(s2, u) ? -1 : 1; 210 } 211 else 212 { 213 // TODO: fix this legacy bad behavior, see 214 // https://issues.dlang.org/show_bug.cgi?id=17244 215 static assert(is(U1 == U2), "Internal error."); 216 import core.stdc.string : memcmp; 217 auto c = (() @trusted => memcmp(&at(s1, u), &at(s2, u), U1.sizeof))(); 218 if (c != 0) 219 return c; 220 } 221 } 222 return s1.length < s2.length ? -1 : (s1.length > s2.length); 223 } 224 225 226 227 /** 228 Destroys the given object and optionally resets to initial state. It's used to 229 _destroy an object, calling its destructor or finalizer so it no longer 230 references any other objects. It does $(I not) initiate a GC cycle or free 231 any GC memory. 232 If `initialize` is supplied `false`, the object is considered invalid after 233 destruction, and should not be referenced. 234 */ 235 void destroy(bool initialize = true, T)(ref T obj) if (is(T == struct)) 236 { 237 _destructRecurse(obj); 238 239 static if (initialize) 240 { 241 // We need to re-initialize `obj`. Previously, an immutable static 242 // and memcpy were used to hold an initializer. With improved unions, this is no longer 243 // needed. 244 union UntypedInit 245 { 246 T dummy; 247 } 248 static struct UntypedStorage 249 { 250 align(T.alignof) void[T.sizeof] dummy; 251 } 252 253 () @trusted { 254 *cast(UntypedStorage*) &obj = cast(UntypedStorage) UntypedInit.init; 255 } (); 256 } 257 } 258 259 @safe unittest 260 { 261 struct A { string s = "A"; } 262 A a = {s: "B"}; 263 assert(a.s == "B"); 264 a.destroy; 265 assert(a.s == "A"); 266 } 267 268 private void _destructRecurse(S)(ref S s) 269 if (is(S == struct)) 270 { 271 static if (__traits(hasMember, S, "__xdtor") && 272 // Bugzilla 14746: Check that it's the exact member of S. 273 __traits(isSame, S, __traits(parent, s.__xdtor))) 274 s.__xdtor(); 275 } 276 277 nothrow @safe @nogc unittest 278 { 279 { 280 struct A { string s = "A"; } 281 A a; 282 a.s = "asd"; 283 destroy!false(a); 284 assert(a.s == "asd"); 285 destroy(a); 286 assert(a.s == "A"); 287 } 288 { 289 static int destroyed = 0; 290 struct C 291 { 292 string s = "C"; 293 ~this() nothrow @safe @nogc 294 { 295 destroyed ++; 296 } 297 } 298 299 struct B 300 { 301 C c; 302 string s = "B"; 303 ~this() nothrow @safe @nogc 304 { 305 destroyed ++; 306 } 307 } 308 B a; 309 a.s = "asd"; 310 a.c.s = "jkl"; 311 destroy!false(a); 312 assert(destroyed == 2); 313 assert(a.s == "asd"); 314 assert(a.c.s == "jkl" ); 315 destroy(a); 316 assert(destroyed == 4); 317 assert(a.s == "B"); 318 assert(a.c.s == "C" ); 319 } 320 } 321 322 /// ditto 323 void destroy(bool initialize = true, T)(T obj) if (is(T == class)) 324 { 325 static if (__traits(getLinkage, T) == "C++") 326 { 327 static if (__traits(hasMember, T, "__xdtor")) 328 obj.__xdtor(); 329 330 static if (initialize) 331 { 332 enum classSize = __traits(classInstanceSize, T); 333 (cast(void*)obj)[0 .. classSize] = typeid(T).initializer[]; 334 } 335 } 336 else 337 rt_finalize(cast(void*)obj); 338 } 339 340 /// ditto 341 void destroy(bool initialize = true, T)(T obj) if (is(T == interface)) 342 { 343 static assert(__traits(getLinkage, T) == "D", "Invalid call to destroy() on extern(" ~ __traits(getLinkage, T) ~ ") interface"); 344 345 destroy!initialize(cast(Object)obj); 346 } 347 348 /// Reference type demonstration 349 @system unittest 350 { 351 class C 352 { 353 struct Agg 354 { 355 static int dtorCount; 356 357 int x = 10; 358 ~this() { dtorCount++; } 359 } 360 361 static int dtorCount; 362 363 string s = "S"; 364 Agg a; 365 ~this() { dtorCount++; } 366 } 367 368 C c = new C(); 369 assert(c.dtorCount == 0); // destructor not yet called 370 assert(c.s == "S"); // initial state `c.s` is `"S"` 371 assert(c.a.dtorCount == 0); // destructor not yet called 372 assert(c.a.x == 10); // initial state `c.a.x` is `10` 373 c.s = "T"; 374 c.a.x = 30; 375 assert(c.s == "T"); // `c.s` is `"T"` 376 destroy(c); 377 assert(c.dtorCount == 1); // `c`'s destructor was called 378 assert(c.s == "S"); // `c.s` is back to its inital state, `"S"` 379 assert(c.a.dtorCount == 1); // `c.a`'s destructor was called 380 assert(c.a.x == 10); // `c.a.x` is back to its inital state, `10` 381 382 // check C++ classes work too! 383 extern (C++) class CPP 384 { 385 struct Agg 386 { 387 __gshared int dtorCount; 388 389 int x = 10; 390 ~this() { dtorCount++; } 391 } 392 393 __gshared int dtorCount; 394 395 string s = "S"; 396 Agg a; 397 ~this() { dtorCount++; } 398 } 399 400 CPP cpp = new CPP(); 401 assert(cpp.dtorCount == 0); // destructor not yet called 402 assert(cpp.s == "S"); // initial state `cpp.s` is `"S"` 403 assert(cpp.a.dtorCount == 0); // destructor not yet called 404 assert(cpp.a.x == 10); // initial state `cpp.a.x` is `10` 405 cpp.s = "T"; 406 cpp.a.x = 30; 407 assert(cpp.s == "T"); // `cpp.s` is `"T"` 408 destroy!false(cpp); // destroy without initialization 409 assert(cpp.dtorCount == 1); // `cpp`'s destructor was called 410 assert(cpp.s == "T"); // `cpp.s` is not initialized 411 assert(cpp.a.dtorCount == 1); // `cpp.a`'s destructor was called 412 assert(cpp.a.x == 30); // `cpp.a.x` is not initialized 413 destroy(cpp); 414 assert(cpp.dtorCount == 2); // `cpp`'s destructor was called again 415 assert(cpp.s == "S"); // `cpp.s` is back to its inital state, `"S"` 416 assert(cpp.a.dtorCount == 2); // `cpp.a`'s destructor was called again 417 assert(cpp.a.x == 10); // `cpp.a.x` is back to its inital state, `10` 418 } 419 420 /// Value type demonstration 421 @safe unittest 422 { 423 int i; 424 assert(i == 0); // `i`'s initial state is `0` 425 i = 1; 426 assert(i == 1); // `i` changed to `1` 427 destroy!false(i); 428 assert(i == 1); // `i` was not initialized 429 destroy(i); 430 assert(i == 0); // `i` is back to its initial state `0` 431 } 432 433 @system unittest 434 { 435 extern(C++) 436 static class C 437 { 438 void* ptr; 439 this() {} 440 } 441 442 destroy!false(new C()); 443 destroy!true(new C()); 444 } 445 446 @system unittest 447 { 448 // class with an `alias this` 449 class A 450 { 451 static int dtorCount; 452 ~this() 453 { 454 dtorCount++; 455 } 456 } 457 458 class B 459 { 460 A a; 461 alias a this; 462 this() 463 { 464 a = new A; 465 } 466 static int dtorCount; 467 ~this() 468 { 469 dtorCount++; 470 } 471 } 472 auto b = new B; 473 assert(A.dtorCount == 0); 474 assert(B.dtorCount == 0); 475 destroy(b); 476 assert(A.dtorCount == 0); 477 assert(B.dtorCount == 1); 478 } 479 480 @system unittest 481 { 482 interface I { } 483 { 484 class A: I { string s = "A"; this() {} } 485 auto a = new A, b = new A; 486 a.s = b.s = "asd"; 487 destroy(a); 488 assert(a.s == "A"); 489 490 I i = b; 491 destroy(i); 492 assert(b.s == "A"); 493 } 494 { 495 static bool destroyed = false; 496 class B: I 497 { 498 string s = "B"; 499 this() {} 500 ~this() 501 { 502 destroyed = true; 503 } 504 } 505 auto a = new B, b = new B; 506 a.s = b.s = "asd"; 507 destroy(a); 508 assert(destroyed); 509 assert(a.s == "B"); 510 511 destroyed = false; 512 I i = b; 513 destroy(i); 514 assert(destroyed); 515 assert(b.s == "B"); 516 } 517 // this test is invalid now that the default ctor is not run after clearing 518 version (none) 519 { 520 class C 521 { 522 string s; 523 this() 524 { 525 s = "C"; 526 } 527 } 528 auto a = new C; 529 a.s = "asd"; 530 destroy(a); 531 assert(a.s == "C"); 532 } 533 } 534 535 nothrow @safe @nogc unittest 536 { 537 { 538 struct A { string s = "A"; } 539 A a; 540 a.s = "asd"; 541 destroy!false(a); 542 assert(a.s == "asd"); 543 destroy(a); 544 assert(a.s == "A"); 545 } 546 { 547 static int destroyed = 0; 548 struct C 549 { 550 string s = "C"; 551 ~this() nothrow @safe @nogc 552 { 553 destroyed ++; 554 } 555 } 556 557 struct B 558 { 559 C c; 560 string s = "B"; 561 ~this() nothrow @safe @nogc 562 { 563 destroyed ++; 564 } 565 } 566 B a; 567 a.s = "asd"; 568 a.c.s = "jkl"; 569 destroy!false(a); 570 assert(destroyed == 2); 571 assert(a.s == "asd"); 572 assert(a.c.s == "jkl" ); 573 destroy(a); 574 assert(destroyed == 4); 575 assert(a.s == "B"); 576 assert(a.c.s == "C" ); 577 } 578 } 579 580 /// ditto 581 void destroy(bool initialize = true, T : U[n], U, size_t n)(ref T obj) if (!is(T == struct)) 582 { 583 foreach_reverse (ref e; obj[]) 584 destroy!initialize(e); 585 } 586 587 @safe unittest 588 { 589 int[2] a; 590 a[0] = 1; 591 a[1] = 2; 592 destroy!false(a); 593 assert(a == [ 1, 2 ]); 594 destroy(a); 595 assert(a == [ 0, 0 ]); 596 } 597 598 @safe unittest 599 { 600 static struct vec2f { 601 float[2] values; 602 alias values this; 603 } 604 605 vec2f v; 606 destroy!(true, vec2f)(v); 607 } 608 609 @system unittest 610 { 611 // Bugzilla 15009 612 static string op; 613 static struct S 614 { 615 int x; 616 this(int x) { op ~= "C" ~ cast(char)('0'+x); this.x = x; } 617 this(this) { op ~= "P" ~ cast(char)('0'+x); } 618 ~this() { op ~= "D" ~ cast(char)('0'+x); } 619 } 620 621 { 622 S[2] a1 = [S(1), S(2)]; 623 op = ""; 624 } 625 assert(op == "D2D1"); // built-in scope destruction 626 { 627 S[2] a1 = [S(1), S(2)]; 628 op = ""; 629 destroy(a1); 630 assert(op == "D2D1"); // consistent with built-in behavior 631 } 632 633 { 634 S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]]; 635 op = ""; 636 } 637 assert(op == "D4D3D2D1"); 638 { 639 S[2][2] a2 = [[S(1), S(2)], [S(3), S(4)]]; 640 op = ""; 641 destroy(a2); 642 assert(op == "D4D3D2D1", op); 643 } 644 } 645 646 /// ditto 647 void destroy(bool initialize = true, T)(ref T obj) 648 if (!is(T == struct) && !is(T == interface) && !is(T == class) && !_isStaticArray!T) 649 { 650 static if (initialize) 651 obj = T.init; 652 } 653 //+/ 654 template _isStaticArray(T : U[N], U, size_t N) 655 { 656 enum bool _isStaticArray = true; 657 } 658 659 template _isStaticArray(T) 660 { 661 enum bool _isStaticArray = false; 662 } 663 /+ 664 @safe unittest 665 { 666 { 667 int a = 42; 668 destroy!false(a); 669 assert(a == 42); 670 destroy(a); 671 assert(a == 0); 672 } 673 { 674 float a = 42; 675 destroy!false(a); 676 assert(a == 42); 677 destroy(a); 678 assert(a != a); // isnan 679 } 680 } 681 682 +/ 683 684 private 685 { 686 Object _d_newclass(const TypeInfo_Class ci) { 687 static assert("not implemented"); 688 return Object.init; 689 } 690 private extern (C) int _d_isbaseof(scope TypeInfo_Class child, 691 scope const TypeInfo_Class parent) @nogc nothrow pure @safe; // rt.cast_ 692 extern (C) void rt_finalize(void *data, bool det=true); 693 } 694 695 696 public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable); 697 /** 698 * All D class objects inherit from Object. 699 */ 700 class Object 701 { 702 /** 703 * Convert Object to a human readable string. 704 */ 705 string toString() 706 { 707 return typeid(this).name; 708 } 709 710 /** 711 * Compute hash function for Object. 712 */ 713 size_t toHash() @trusted nothrow 714 { 715 // BUG: this prevents a compacting GC from working, needs to be fixed 716 size_t addr = cast(size_t) cast(void*) this; 717 // The bottom log2((void*).alignof) bits of the address will always 718 // be 0. Moreover it is likely that each Object is allocated with a 719 // separate call to malloc. The alignment of malloc differs from 720 // platform to platform, but rather than having special cases for 721 // each platform it is safe to use a shift of 4. To minimize 722 // collisions in the low bits it is more important for the shift to 723 // not be too small than for the shift to not be too big. 724 return addr ^ (addr >>> 4); 725 } 726 727 /** 728 * Compare with another Object obj. 729 * Returns: 730 * $(TABLE 731 * $(TR $(TD this < obj) $(TD < 0)) 732 * $(TR $(TD this == obj) $(TD 0)) 733 * $(TR $(TD this > obj) $(TD > 0)) 734 * ) 735 */ 736 int opCmp(Object o) 737 { 738 // BUG: this prevents a compacting GC from working, needs to be fixed 739 //return cast(int)cast(void*)this - cast(int)cast(void*)o; 740 741 assert(false); 742 // throw new Exception("need opCmp for class " ~ typeid(this).name); 743 //return this !is o; 744 } 745 746 /** 747 * Test whether $(D this) is equal to $(D o). 748 * The default implementation only compares by identity (using the $(D is) operator). 749 * Generally, overrides for $(D opEquals) should attempt to compare objects by their contents. 750 */ 751 bool opEquals(Object o) 752 { 753 return this is o; 754 } 755 756 interface Monitor 757 { 758 void lock(); 759 void unlock(); 760 } 761 762 /** 763 * Create instance of class specified by the fully qualified name 764 * classname. 765 * The class must either have no constructors or have 766 * a default constructor. 767 * Returns: 768 * null if failed 769 * Example: 770 * --- 771 * module foo.bar; 772 * 773 * class C 774 * { 775 * this() { x = 10; } 776 * int x; 777 * } 778 * 779 * void main() 780 * { 781 * auto c = cast(C)Object.factory("foo.bar.C"); 782 * assert(c !is null && c.x == 10); 783 * } 784 * --- 785 */ 786 static Object factory(string classname) 787 { 788 auto ci = TypeInfo_Class.find(classname); 789 if (ci) 790 { 791 return ci.create(); 792 } 793 return null; 794 } 795 } 796 797 798 /++ 799 Implementation for class opEquals override. Calls the class-defined methods after a null check. 800 Please note this is not nogc right now, even if your implementation is, because of 801 the typeinfo name string compare. This is because of dmd's dll implementation. However, 802 it can infer to @safe if your class' opEquals is. 803 +/ 804 bool opEquals(LHS, RHS)(LHS lhs, RHS rhs) 805 if ((is(LHS : const Object) || is(LHS : const shared Object)) && 806 (is(RHS : const Object) || is(RHS : const shared Object))) 807 { 808 static if (__traits(compiles, lhs.opEquals(rhs)) && __traits(compiles, rhs.opEquals(lhs))) 809 { 810 // If aliased to the same object or both null => equal 811 if (lhs is rhs) return true; 812 813 // If either is null => non-equal 814 if (lhs is null || rhs is null) return false; 815 816 if (!lhs.opEquals(rhs)) return false; 817 818 // If same exact type => one call to method opEquals 819 if (typeid(lhs) is typeid(rhs) || 820 !__ctfe && typeid(lhs).opEquals(typeid(rhs))) 821 /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't: 822 https://issues.dlang.org/show_bug.cgi?id=7147 823 But CTFE also guarantees that equal TypeInfos are 824 always identical. So, no opEquals needed during CTFE. */ 825 { 826 return true; 827 } 828 829 // General case => symmetric calls to method opEquals 830 return rhs.opEquals(lhs); 831 } 832 else 833 { 834 // this is a compatibility hack for the old const cast behavior 835 // if none of the new overloads compile, we'll go back plain Object, 836 // including casting away const. It does this through the pointer 837 // to bypass any opCast that may be present on the original class. 838 return .opEquals!(Object, Object)(*cast(Object*) &lhs, *cast(Object*) &rhs); 839 840 } 841 } 842 /+ 843 bool opEquals(Object lhs, Object rhs) 844 { 845 // If aliased to the same object or both null => equal 846 if (lhs is rhs) return true; 847 848 // If either is null => non-equal 849 if (lhs is null || rhs is null) return false; 850 851 // If same exact type => one call to method opEquals 852 if (typeid(lhs) is typeid(rhs) || 853 !__ctfe && typeid(lhs).opEquals(typeid(rhs))) 854 /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't 855 (issue 7147). But CTFE also guarantees that equal TypeInfos are 856 always identical. So, no opEquals needed during CTFE. */ 857 { 858 return lhs.opEquals(rhs); 859 } 860 861 // General case => symmetric calls to method opEquals 862 return lhs.opEquals(rhs) && rhs.opEquals(lhs); 863 } 864 865 /************************ 866 * Returns true if lhs and rhs are equal. 867 */ 868 bool opEquals(const Object lhs, const Object rhs) 869 { 870 // A hack for the moment. 871 return opEquals(cast()lhs, cast()rhs); 872 } 873 874 /// If aliased to the same object or both null => equal 875 @system unittest 876 { 877 class F { int flag; this(int flag) { this.flag = flag; } } 878 879 F f; 880 assert(f == f); // both null 881 f = new F(1); 882 assert(f == f); // both aliased to the same object 883 } 884 885 /// If either is null => non-equal 886 @system unittest 887 { 888 class F { int flag; this(int flag) { this.flag = flag; } } 889 F f; 890 assert(!(new F(0) == f)); 891 assert(!(f == new F(0))); 892 } 893 894 /// If same exact type => one call to method opEquals 895 @system unittest 896 { 897 class F 898 { 899 int flag; 900 901 this(int flag) 902 { 903 this.flag = flag; 904 } 905 906 override bool opEquals(const Object o) 907 { 908 return flag == (cast(F) o).flag; 909 } 910 } 911 912 F f; 913 assert(new F(0) == new F(0)); 914 assert(!(new F(0) == new F(1))); 915 } 916 917 /// General case => symmetric calls to method opEquals 918 @system unittest 919 { 920 int fEquals, gEquals; 921 922 class Base 923 { 924 int flag; 925 this(int flag) 926 { 927 this.flag = flag; 928 } 929 } 930 931 class F : Base 932 { 933 this(int flag) { super(flag); } 934 935 override bool opEquals(const Object o) 936 { 937 fEquals++; 938 return flag == (cast(Base) o).flag; 939 } 940 } 941 942 class G : Base 943 { 944 this(int flag) { super(flag); } 945 946 override bool opEquals(const Object o) 947 { 948 gEquals++; 949 return flag == (cast(Base) o).flag; 950 } 951 } 952 953 assert(new F(1) == new G(1)); 954 assert(fEquals == 1); 955 assert(gEquals == 1); 956 } 957 958 private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow; 959 960 void setSameMutex(shared Object ownee, shared Object owner) 961 { 962 _d_setSameMutex(ownee, owner); 963 } 964 +/ 965 966 /** 967 * Information about an interface. 968 * When an object is accessed via an interface, an Interface* appears as the 969 * first entry in its vtbl. 970 */ 971 struct Interface 972 { 973 TypeInfo_Class classinfo; /// .classinfo for this interface (not for containing class) 974 void*[] vtbl; 975 size_t offset; /// offset to Interface 'this' from Object 'this' 976 } 977 978 /** 979 * Array of pairs giving the offset and type information for each 980 * member in an aggregate. 981 */ 982 struct OffsetTypeInfo 983 { 984 size_t offset; /// Offset of member from start of object 985 TypeInfo ti; /// TypeInfo for this member 986 } 987 /** 988 * Runtime type information about a type. 989 * Can be retrieved for any type using a 990 * $(GLINK2 expression,TypeidExpression, TypeidExpression). 991 */ 992 class TypeInfo 993 { 994 override string toString() const @safe nothrow 995 { 996 return typeid(this).name; 997 } 998 999 override size_t toHash() @trusted const nothrow 1000 { 1001 return hashOf(this.toString()); 1002 } 1003 1004 1005 1006 override bool opEquals(Object o) 1007 { 1008 return opEquals(cast(TypeInfo) o); 1009 } 1010 1011 bool opEquals(const TypeInfo ti) @safe nothrow const 1012 { 1013 /* TypeInfo instances are singletons, but duplicates can exist 1014 * across DLL's. Therefore, comparing for a name match is 1015 * sufficient. 1016 */ 1017 if (this is ti) 1018 return true; 1019 return ti && this.toString() == ti.toString(); 1020 } 1021 1022 1023 /** 1024 * Computes a hash of the instance of a type. 1025 * Params: 1026 * p = pointer to start of instance of the type 1027 * Returns: 1028 * the hash 1029 * Bugs: 1030 * fix https://issues.dlang.org/show_bug.cgi?id=12516 e.g. by changing this to a truly safe interface. 1031 */ 1032 size_t getHash(scope const void* p) @trusted nothrow const 1033 { 1034 return hashOf(p); 1035 } 1036 1037 /// Compares two instances for equality. 1038 bool equals(in void* p1, in void* p2) const { return p1 == p2; } 1039 1040 /// Compares two instances for <, ==, or >. 1041 int compare(in void* p1, in void* p2) const { return _xopCmp(p1, p2); } 1042 1043 /// Returns size of the type. 1044 @property size_t tsize() nothrow pure const @safe @nogc { return 0; } 1045 1046 /// Swaps two instances of the type. 1047 void swap(void* p1, void* p2) const 1048 { 1049 immutable size_t n = tsize; 1050 for (size_t i = 0; i < n; i++) 1051 { 1052 byte t = (cast(byte *)p1)[i]; 1053 (cast(byte*)p1)[i] = (cast(byte*)p2)[i]; 1054 (cast(byte*)p2)[i] = t; 1055 } 1056 } 1057 1058 /** Get TypeInfo for 'next' type, as defined by what kind of type this is, 1059 null if none. */ 1060 @property inout(TypeInfo) next() nothrow pure inout @nogc { return null; } 1061 1062 /** 1063 * Return default initializer. If the type should be initialized to all 1064 * zeros, an array with a null ptr and a length equal to the type size will 1065 * be returned. For static arrays, this returns the default initializer for 1066 * a single element of the array, use `tsize` to get the correct size. 1067 */ 1068 version (LDC) 1069 { 1070 // LDC uses TypeInfo's vtable for the typeof(null) type: 1071 // %"typeid(typeof(null))" = type { %object.TypeInfo.__vtbl*, i8* } 1072 // Therefore this class cannot be abstract, and all methods need implementations. 1073 // Tested by test14754() in runnable/inline.d, and a unittest below. 1074 const(void)[] initializer() nothrow pure const @trusted @nogc 1075 { 1076 return (cast(const(void)*) null)[0 .. typeof(null).sizeof]; 1077 } 1078 } 1079 else 1080 { 1081 abstract const(void)[] initializer() nothrow pure const @safe @nogc; 1082 } 1083 1084 /** Get flags for type: 1 means GC should scan for pointers, 1085 2 means arg of this type is passed in XMM register */ 1086 @property uint flags() nothrow pure const @safe @nogc { return 0; } 1087 1088 /// Get type information on the contents of the type; null if not available 1089 const(OffsetTypeInfo)[] offTi() const { return null; } 1090 /// Run the destructor on the object and all its sub-objects 1091 void destroy(void* p) const {} 1092 /// Run the postblit on the object and all its sub-objects 1093 void postblit(void* p) const {} 1094 1095 1096 /// Return alignment of type 1097 @property size_t talign() nothrow pure const @safe @nogc { return tsize; } 1098 1099 /** Return internal info on arguments fitting into 8byte. 1100 * See X86-64 ABI 3.2.3 1101 */ 1102 version (X86_64) int argTypes(out TypeInfo arg1, out TypeInfo arg2) @safe nothrow 1103 { 1104 arg1 = this; 1105 return 0; 1106 } 1107 1108 /** Return info used by the garbage collector to do precise collection. 1109 */ 1110 @property immutable(void)* rtInfo() nothrow pure const @safe @nogc { return rtinfoHasPointers; } // better safe than sorry 1111 } 1112 1113 private size_t getArrayHash(const scope TypeInfo element, const scope void* ptr, const size_t count) @trusted nothrow 1114 { 1115 if (!count) 1116 return 0; 1117 1118 const size_t elementSize = element.tsize; 1119 if (!elementSize) 1120 return 0; 1121 1122 static bool hasCustomToHash(const scope TypeInfo value) @trusted pure nothrow 1123 { 1124 const element = getElement(value); 1125 1126 if (const struct_ = cast(const TypeInfo_Struct) element) 1127 return !!struct_.xtoHash; 1128 1129 return cast(const TypeInfo_Array) element 1130 || cast(const TypeInfo_AssociativeArray) element 1131 || cast(const ClassInfo) element 1132 || cast(const TypeInfo_Interface) element; 1133 } 1134 1135 if (!hasCustomToHash(element)) 1136 return hashOf(ptr[0 .. elementSize * count]); 1137 1138 size_t hash = 0; 1139 foreach (size_t i; 0 .. count) 1140 hash = hashOf(element.getHash(ptr + i * elementSize), hash); 1141 return hash; 1142 } 1143 1144 class TypeInfo_Array : TypeInfo 1145 { 1146 override string toString() const { return value.toString() ~ "[]"; } 1147 override bool opEquals(Object o) 1148 { 1149 if (this is o) 1150 return true; 1151 auto c = cast(const TypeInfo_Array)o; 1152 return c && this.value == c.value; 1153 } 1154 1155 override size_t getHash(scope const void* p) @trusted const 1156 { 1157 void[] a = *cast(void[]*)p; 1158 return getArrayHash(value, a.ptr, a.length); 1159 } 1160 1161 override bool equals(in void* p1, in void* p2) const 1162 { 1163 void[] a1 = *cast(void[]*)p1; 1164 void[] a2 = *cast(void[]*)p2; 1165 if (a1.length != a2.length) 1166 return false; 1167 size_t sz = value.tsize; 1168 for (size_t i = 0; i < a1.length; i++) 1169 { 1170 if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz)) 1171 return false; 1172 } 1173 return true; 1174 } 1175 1176 override int compare(in void* p1, in void* p2) const 1177 { 1178 void[] a1 = *cast(void[]*)p1; 1179 void[] a2 = *cast(void[]*)p2; 1180 size_t sz = value.tsize; 1181 size_t len = a1.length; 1182 1183 if (a2.length < len) 1184 len = a2.length; 1185 for (size_t u = 0; u < len; u++) 1186 { 1187 immutable int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz); 1188 if (result) 1189 return result; 1190 } 1191 return cast(int)a1.length - cast(int)a2.length; 1192 } 1193 1194 override @property size_t tsize() nothrow pure const 1195 { 1196 return (void[]).sizeof; 1197 } 1198 1199 override const(void)[] initializer() const @trusted 1200 { 1201 return (cast(void *)null)[0 .. (void[]).sizeof]; 1202 } 1203 1204 override void swap(void* p1, void* p2) const 1205 { 1206 void[] tmp = *cast(void[]*)p1; 1207 *cast(void[]*)p1 = *cast(void[]*)p2; 1208 *cast(void[]*)p2 = tmp; 1209 } 1210 1211 TypeInfo value; 1212 1213 override @property inout(TypeInfo) next() nothrow pure inout 1214 { 1215 return value; 1216 } 1217 1218 override @property uint flags() nothrow pure const { return 1; } 1219 1220 override @property size_t talign() nothrow pure const 1221 { 1222 return (void[]).alignof; 1223 } 1224 1225 version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 1226 { 1227 arg1 = typeid(size_t); 1228 arg2 = typeid(void*); 1229 return 0; 1230 } 1231 1232 override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(void[]); } 1233 } 1234 1235 class TypeInfo_Delegate : TypeInfo 1236 { 1237 1238 override string toString() const pure @trusted 1239 { 1240 import core.demangle : demangleType; 1241 1242 alias SafeDemangleFunctionType = char[] function (const(char)[] buf, char[] dst = null) @safe nothrow pure; 1243 SafeDemangleFunctionType demangle = cast(SafeDemangleFunctionType) &demangleType; 1244 1245 return cast(string) demangle(deco); 1246 } 1247 override bool opEquals(Object o) 1248 { 1249 if (this is o) 1250 return true; 1251 auto c = cast(const TypeInfo_Delegate)o; 1252 return c && this.deco == c.deco; 1253 } 1254 1255 override size_t getHash(scope const void* p) @trusted const 1256 { 1257 return hashOf(*cast(const void delegate() *)p); 1258 } 1259 1260 override bool equals(in void* p1, in void* p2) const 1261 { 1262 auto dg1 = *cast(void delegate()*)p1; 1263 auto dg2 = *cast(void delegate()*)p2; 1264 return dg1 == dg2; 1265 } 1266 1267 override int compare(in void* p1, in void* p2) const 1268 { 1269 auto dg1 = *cast(void delegate()*)p1; 1270 auto dg2 = *cast(void delegate()*)p2; 1271 1272 if (dg1 < dg2) 1273 return -1; 1274 else if (dg1 > dg2) 1275 return 1; 1276 else 1277 return 0; 1278 } 1279 1280 override @property size_t tsize() nothrow pure const 1281 { 1282 alias dg = int delegate(); 1283 return dg.sizeof; 1284 } 1285 1286 override const(void)[] initializer() const @trusted 1287 { 1288 return (cast(void *)null)[0 .. (int delegate()).sizeof]; 1289 } 1290 1291 override @property uint flags() nothrow pure const { return 1; } 1292 1293 TypeInfo next; 1294 string deco; 1295 1296 override @property size_t talign() nothrow pure const 1297 { 1298 alias dg = int delegate(); 1299 return dg.alignof; 1300 } 1301 1302 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 1303 { 1304 arg1 = typeid(void*); 1305 arg2 = typeid(void*); 1306 return 0; 1307 } 1308 1309 override @property immutable(void)* rtInfo() nothrow pure const @safe { return RTInfo!(int delegate()); } 1310 } 1311 1312 class TypeInfo_Enum : TypeInfo 1313 { 1314 override string toString() const { return name; } 1315 1316 override bool opEquals(Object o) 1317 { 1318 if (this is o) 1319 return true; 1320 auto c = cast(const TypeInfo_Enum)o; 1321 return c && this.name == c.name && 1322 this.base == c.base; 1323 } 1324 1325 override size_t getHash(scope const void* p) const { return base.getHash(p); } 1326 override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); } 1327 override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); } 1328 override @property size_t tsize() nothrow pure const { return base.tsize; } 1329 override void swap(void* p1, void* p2) const { return base.swap(p1, p2); } 1330 1331 override @property inout(TypeInfo) next() nothrow pure inout { return base.next; } 1332 override @property uint flags() nothrow pure const { return base.flags; } 1333 1334 override const(void)[] initializer() const 1335 { 1336 return m_init.length ? m_init : base.initializer(); 1337 } 1338 1339 override @property size_t talign() nothrow pure const { return base.talign; } 1340 1341 version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 1342 { 1343 return base.argTypes(arg1, arg2); 1344 } 1345 1346 override @property immutable(void)* rtInfo() const { return base.rtInfo; } 1347 1348 TypeInfo base; 1349 string name; 1350 void[] m_init; 1351 } 1352 1353 1354 class TypeInfo_StaticArray : TypeInfo 1355 { 1356 override string toString() const 1357 { 1358 import core.internal.string : unsignedToTempString; 1359 1360 char[20] tmpBuff = void; 1361 const lenString = unsignedToTempString(len, tmpBuff); 1362 1363 return (() @trusted => cast(string) (value.toString() ~ "[" ~ lenString ~ "]"))(); 1364 } 1365 1366 override bool opEquals(Object o) 1367 { 1368 if (this is o) 1369 return true; 1370 auto c = cast(const TypeInfo_StaticArray)o; 1371 return c && this.len == c.len && 1372 this.value == c.value; 1373 } 1374 1375 override bool equals(in void* p1, in void* p2) const 1376 { 1377 size_t sz = value.tsize; 1378 1379 for (size_t u = 0; u < len; u++) 1380 { 1381 if (!value.equals(p1 + u * sz, p2 + u * sz)) 1382 return false; 1383 } 1384 return true; 1385 } 1386 1387 override int compare(in void* p1, in void* p2) const 1388 { 1389 size_t sz = value.tsize; 1390 1391 for (size_t u = 0; u < len; u++) 1392 { 1393 immutable int result = value.compare(p1 + u * sz, p2 + u * sz); 1394 if (result) 1395 return result; 1396 } 1397 return 0; 1398 } 1399 1400 override @property size_t tsize() nothrow pure const 1401 { 1402 return len * value.tsize; 1403 } 1404 1405 override const(void)[] initializer() nothrow pure const 1406 { 1407 return value.initializer(); 1408 } 1409 1410 override @property inout(TypeInfo) next() nothrow pure inout { return value; } 1411 override @property uint flags() nothrow pure const { return value.flags; } 1412 1413 override void destroy(void* p) const 1414 { 1415 immutable sz = value.tsize; 1416 p += sz * len; 1417 foreach (i; 0 .. len) 1418 { 1419 p -= sz; 1420 value.destroy(p); 1421 } 1422 } 1423 1424 override void postblit(void* p) const 1425 { 1426 immutable sz = value.tsize; 1427 foreach (i; 0 .. len) 1428 { 1429 value.postblit(p); 1430 p += sz; 1431 } 1432 } 1433 1434 override void swap(void* p1, void* p2) const 1435 { 1436 import core.stdc.string : memcpy; 1437 1438 size_t remaining = value.tsize * len; 1439 void[size_t.sizeof * 4] buffer = void; 1440 while (remaining > buffer.length) 1441 { 1442 memcpy(buffer.ptr, p1, buffer.length); 1443 memcpy(p1, p2, buffer.length); 1444 memcpy(p2, buffer.ptr, buffer.length); 1445 p1 += buffer.length; 1446 p2 += buffer.length; 1447 remaining -= buffer.length; 1448 } 1449 memcpy(buffer.ptr, p1, remaining); 1450 memcpy(p1, p2, remaining); 1451 memcpy(p2, buffer.ptr, remaining); 1452 } 1453 1454 TypeInfo value; 1455 size_t len; 1456 1457 override @property size_t talign() nothrow pure const 1458 { 1459 return value.talign; 1460 } 1461 1462 version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 1463 { 1464 arg1 = typeid(void*); 1465 return 0; 1466 } 1467 1468 // just return the rtInfo of the element, we have no generic type T to run RTInfo!T on 1469 override @property immutable(void)* rtInfo() nothrow pure const @safe { return value.rtInfo(); } 1470 } 1471 1472 // Please make sure to keep this in sync with TypeInfo_P (src/rt/typeinfo/ti_ptr.d) 1473 class TypeInfo_Pointer : TypeInfo 1474 { 1475 override string toString() const { return m_next.toString() ~ "*"; } 1476 1477 override bool opEquals(Object o) 1478 { 1479 if (this is o) 1480 return true; 1481 auto c = cast(const TypeInfo_Pointer)o; 1482 return c && this.m_next == c.m_next; 1483 } 1484 1485 override size_t getHash(scope const void* p) @trusted const 1486 { 1487 size_t addr = cast(size_t) *cast(const void**)p; 1488 return addr ^ (addr >> 4); 1489 } 1490 1491 override bool equals(in void* p1, in void* p2) const 1492 { 1493 return *cast(void**)p1 == *cast(void**)p2; 1494 } 1495 1496 override int compare(in void* p1, in void* p2) const 1497 { 1498 const v1 = *cast(void**) p1, v2 = *cast(void**) p2; 1499 return (v1 > v2) - (v1 < v2); 1500 } 1501 1502 override @property size_t tsize() nothrow pure const 1503 { 1504 return (void*).sizeof; 1505 } 1506 1507 override const(void)[] initializer() const @trusted 1508 { 1509 return (cast(void *)null)[0 .. (void*).sizeof]; 1510 } 1511 1512 override void swap(void* p1, void* p2) const 1513 { 1514 void* tmp = *cast(void**)p1; 1515 *cast(void**)p1 = *cast(void**)p2; 1516 *cast(void**)p2 = tmp; 1517 } 1518 1519 override @property inout(TypeInfo) next() nothrow pure inout { return m_next; } 1520 override @property uint flags() nothrow pure const { return 1; } 1521 1522 TypeInfo m_next; 1523 } 1524 1525 class TypeInfo_AssociativeArray : TypeInfo 1526 { 1527 override string toString() const 1528 { 1529 return value.toString() ~ "[" ~ key.toString() ~ "]"; 1530 } 1531 1532 override bool opEquals(Object o) 1533 { 1534 if (this is o) 1535 return true; 1536 auto c = cast(const TypeInfo_AssociativeArray)o; 1537 return c && this.key == c.key && 1538 this.value == c.value; 1539 } 1540 1541 override bool equals(in void* p1, in void* p2) @trusted const 1542 { 1543 return !!_aaEqual(this, *cast(const AA*) p1, *cast(const AA*) p2); 1544 } 1545 1546 override hash_t getHash(scope const void* p) nothrow @trusted const 1547 { 1548 return _aaGetHash(cast(AA*)p, this); 1549 } 1550 1551 // BUG: need to add the rest of the functions 1552 1553 override @property size_t tsize() nothrow pure const 1554 { 1555 return (char[int]).sizeof; 1556 } 1557 1558 override const(void)[] initializer() const @trusted 1559 { 1560 return (cast(void *)null)[0 .. (char[int]).sizeof]; 1561 } 1562 1563 override @property inout(TypeInfo) next() nothrow pure inout { return value; } 1564 override @property uint flags() nothrow pure const { return 1; } 1565 1566 TypeInfo value; 1567 TypeInfo key; 1568 1569 override @property size_t talign() nothrow pure const 1570 { 1571 return (char[int]).alignof; 1572 } 1573 1574 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 1575 { 1576 arg1 = typeid(void*); 1577 return 0; 1578 } 1579 } 1580 1581 class TypeInfo_Vector : TypeInfo 1582 { 1583 override string toString() const { return "__vector(" ~ base.toString() ~ ")"; } 1584 override bool opEquals(Object o) 1585 { 1586 if (this is o) 1587 return true; 1588 auto c = cast(const TypeInfo_Vector)o; 1589 return c && this.base == c.base; 1590 } 1591 1592 override size_t getHash(scope const void* p) const { return base.getHash(p); } 1593 override bool equals(in void* p1, in void* p2) const { return base.equals(p1, p2); } 1594 override int compare(in void* p1, in void* p2) const { return base.compare(p1, p2); } 1595 override @property size_t tsize() nothrow pure const { return base.tsize; } 1596 override void swap(void* p1, void* p2) const { return base.swap(p1, p2); } 1597 1598 override @property inout(TypeInfo) next() nothrow pure inout { return base.next; } 1599 override @property uint flags() nothrow pure const { return base.flags; } 1600 1601 override const(void)[] initializer() nothrow pure const 1602 { 1603 return base.initializer(); 1604 } 1605 1606 override @property size_t talign() nothrow pure const { return 16; } 1607 1608 version (X86_64) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 1609 { 1610 return base.argTypes(arg1, arg2); 1611 } 1612 1613 TypeInfo base; 1614 } 1615 1616 class TypeInfo_Function : TypeInfo 1617 { 1618 override string toString() const pure @trusted 1619 { 1620 import core.demangle : demangleType; 1621 1622 alias SafeDemangleFunctionType = char[] function (const(char)[] buf, char[] dst = null) @safe nothrow pure; 1623 SafeDemangleFunctionType demangle = cast(SafeDemangleFunctionType) &demangleType; 1624 1625 return cast(string) demangle(deco); 1626 } 1627 1628 override bool opEquals(Object o) 1629 { 1630 if (this is o) 1631 return true; 1632 auto c = cast(const TypeInfo_Function)o; 1633 return c && this.deco == c.deco; 1634 } 1635 1636 // BUG: need to add the rest of the functions 1637 1638 override @property size_t tsize() nothrow pure const 1639 { 1640 return 0; // no size for functions 1641 } 1642 1643 override const(void)[] initializer() const @safe 1644 { 1645 return null; 1646 } 1647 1648 override @property immutable(void)* rtInfo() nothrow pure const @safe { return rtinfoNoPointers; } 1649 1650 TypeInfo next; 1651 1652 /** 1653 * Mangled function type string 1654 */ 1655 string deco; 1656 } 1657 1658 /** 1659 * Runtime type information about a class. 1660 * Can be retrieved from an object instance by using the 1661 * $(DDSUBLINK spec/property,classinfo, .classinfo) property. 1662 */ 1663 class TypeInfo_Class : TypeInfo 1664 { 1665 override string toString() const { return info.name; } 1666 1667 override bool opEquals(Object o) 1668 { 1669 if (this is o) 1670 return true; 1671 auto c = cast(const TypeInfo_Class)o; 1672 return c && this.info.name == c.info.name; 1673 } 1674 1675 override size_t getHash(scope const void* p) @trusted const 1676 { 1677 auto o = *cast(Object*)p; 1678 return o ? o.toHash() : 0; 1679 } 1680 1681 override bool equals(in void* p1, in void* p2) const 1682 { 1683 Object o1 = *cast(Object*)p1; 1684 Object o2 = *cast(Object*)p2; 1685 1686 return (o1 is o2) || (o1 && o1.opEquals(o2)); 1687 } 1688 1689 override int compare(in void* p1, in void* p2) const 1690 { 1691 Object o1 = *cast(Object*)p1; 1692 Object o2 = *cast(Object*)p2; 1693 int c = 0; 1694 1695 // Regard null references as always being "less than" 1696 if (o1 !is o2) 1697 { 1698 if (o1) 1699 { 1700 if (!o2) 1701 c = 1; 1702 else 1703 c = o1.opCmp(o2); 1704 } 1705 else 1706 c = -1; 1707 } 1708 return c; 1709 } 1710 1711 override @property size_t tsize() nothrow pure const 1712 { 1713 return Object.sizeof; 1714 } 1715 1716 override const(void)[] initializer() nothrow pure const @safe 1717 { 1718 return m_init; 1719 } 1720 1721 override @property uint flags() nothrow pure const { return 1; } 1722 1723 override @property const(OffsetTypeInfo)[] offTi() nothrow pure const 1724 { 1725 return m_offTi; 1726 } 1727 1728 @property auto info() @safe nothrow pure const { return this; } 1729 @property auto typeinfo() @safe nothrow pure const { return this; } 1730 1731 byte[] m_init; /** class static initializer 1732 * (init.length gives size in bytes of class) 1733 */ 1734 string name; /// class name 1735 void*[] vtbl; /// virtual function pointer table 1736 Interface[] interfaces; /// interfaces this class implements 1737 TypeInfo_Class base; /// base class 1738 void* destructor; 1739 void function(Object) classInvariant; 1740 enum ClassFlags : uint 1741 { 1742 isCOMclass = 0x1, 1743 noPointers = 0x2, 1744 hasOffTi = 0x4, 1745 hasCtor = 0x8, 1746 hasGetMembers = 0x10, 1747 hasTypeInfo = 0x20, 1748 isAbstract = 0x40, 1749 isCPPclass = 0x80, 1750 hasDtor = 0x100, 1751 } 1752 ClassFlags m_flags; 1753 void* deallocator; 1754 OffsetTypeInfo[] m_offTi; 1755 void function(Object) defaultConstructor; // default Constructor 1756 1757 immutable(void)* m_RTInfo; // data for precise GC 1758 override @property immutable(void)* rtInfo() const { return m_RTInfo; } 1759 1760 /** 1761 * Search all modules for TypeInfo_Class corresponding to classname. 1762 * Returns: null if not found 1763 */ 1764 static const(TypeInfo_Class) find(const scope char[] classname) 1765 { 1766 foreach (m; ModuleInfo) 1767 { 1768 if (m) 1769 { 1770 //writefln("module %s, %d", m.name, m.localClasses.length); 1771 foreach (c; m.localClasses) 1772 { 1773 if (c is null) 1774 continue; 1775 //writefln("\tclass %s", c.name); 1776 if (c.name == classname) 1777 return c; 1778 } 1779 } 1780 } 1781 return null; 1782 } 1783 /** 1784 * Create instance of Object represented by 'this'. 1785 */ 1786 Object create() const 1787 { 1788 if (m_flags & 8 && !defaultConstructor) 1789 return null; 1790 if (m_flags & 64) // abstract 1791 return null; 1792 Object o = _d_newclass(this); 1793 if (m_flags & 8 && defaultConstructor) 1794 { 1795 defaultConstructor(o); 1796 } 1797 return o; 1798 } 1799 /** 1800 * Returns true if the class described by `child` derives from or is 1801 * the class described by this `TypeInfo_Class`. Always returns false 1802 * if the argument is null. 1803 * 1804 * Params: 1805 * child = TypeInfo for some class 1806 * Returns: 1807 * true if the class described by `child` derives from or is the 1808 * class described by this `TypeInfo_Class`. 1809 */ 1810 final bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted 1811 { 1812 if (m_init.length) 1813 { 1814 // If this TypeInfo_Class represents an actual class we only need 1815 // to check the child and its direct ancestors. 1816 for (auto ti = cast() child; ti !is null; ti = ti.base) 1817 if (ti is this) 1818 return true; 1819 return false; 1820 } 1821 else 1822 { 1823 // If this TypeInfo_Class is the .info field of a TypeInfo_Interface 1824 // we also need to recursively check the child's interfaces. 1825 return child !is null && _d_isbaseof(cast() child, this); 1826 } 1827 } 1828 } 1829 1830 alias ClassInfo = TypeInfo_Class; 1831 1832 class TypeInfo_Interface : TypeInfo 1833 { 1834 override string toString() const { return info.name; } 1835 1836 override bool opEquals(Object o) 1837 { 1838 if (this is o) 1839 return true; 1840 auto c = cast(const TypeInfo_Interface)o; 1841 return c && this.info.name == typeid(c).name; 1842 } 1843 1844 override size_t getHash(scope const void* p) @trusted const 1845 { 1846 if (!*cast(void**)p) 1847 { 1848 return 0; 1849 } 1850 Interface* pi = **cast(Interface ***)*cast(void**)p; 1851 Object o = cast(Object)(*cast(void**)p - pi.offset); 1852 assert(o); 1853 return o.toHash(); 1854 } 1855 1856 override bool equals(in void* p1, in void* p2) const 1857 { 1858 Interface* pi = **cast(Interface ***)*cast(void**)p1; 1859 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); 1860 pi = **cast(Interface ***)*cast(void**)p2; 1861 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); 1862 1863 return o1 == o2 || (o1 && o1.opCmp(o2) == 0); 1864 } 1865 1866 override int compare(in void* p1, in void* p2) const 1867 { 1868 Interface* pi = **cast(Interface ***)*cast(void**)p1; 1869 Object o1 = cast(Object)(*cast(void**)p1 - pi.offset); 1870 pi = **cast(Interface ***)*cast(void**)p2; 1871 Object o2 = cast(Object)(*cast(void**)p2 - pi.offset); 1872 int c = 0; 1873 1874 // Regard null references as always being "less than" 1875 if (o1 != o2) 1876 { 1877 if (o1) 1878 { 1879 if (!o2) 1880 c = 1; 1881 else 1882 c = o1.opCmp(o2); 1883 } 1884 else 1885 c = -1; 1886 } 1887 return c; 1888 } 1889 1890 override @property size_t tsize() nothrow pure const 1891 { 1892 return Object.sizeof; 1893 } 1894 1895 override const(void)[] initializer() const @trusted 1896 { 1897 return (cast(void *)null)[0 .. Object.sizeof]; 1898 } 1899 1900 override @property uint flags() nothrow pure const { return 1; } 1901 1902 TypeInfo_Class info; 1903 1904 /** 1905 * Returns true if the class described by `child` derives from the 1906 * interface described by this `TypeInfo_Interface`. Always returns 1907 * false if the argument is null. 1908 * 1909 * Params: 1910 * child = TypeInfo for some class 1911 * Returns: 1912 * true if the class described by `child` derives from the 1913 * interface described by this `TypeInfo_Interface`. 1914 */ 1915 final bool isBaseOf(scope const TypeInfo_Class child) const @nogc nothrow pure @trusted 1916 { 1917 return child !is null && _d_isbaseof(cast() child, this.info); 1918 } 1919 1920 /** 1921 * Returns true if the interface described by `child` derives from 1922 * or is the interface described by this `TypeInfo_Interface`. 1923 * Always returns false if the argument is null. 1924 * 1925 * Params: 1926 * child = TypeInfo for some interface 1927 * Returns: 1928 * true if the interface described by `child` derives from or is 1929 * the interface described by this `TypeInfo_Interface`. 1930 */ 1931 final bool isBaseOf(scope const TypeInfo_Interface child) const @nogc nothrow pure @trusted 1932 { 1933 return child !is null && _d_isbaseof(cast() child.info, this.info); 1934 } 1935 } 1936 1937 1938 @system unittest 1939 { 1940 struct S 1941 { 1942 bool opEquals(ref const S rhs) const 1943 { 1944 return false; 1945 } 1946 } 1947 S s; 1948 assert(!typeid(S).equals(&s, &s)); 1949 } 1950 1951 class TypeInfo_Tuple : TypeInfo 1952 { 1953 TypeInfo[] elements; 1954 1955 override string toString() const 1956 { 1957 string s = "("; 1958 foreach (i, element; elements) 1959 { 1960 if (i) 1961 s ~= ','; 1962 s ~= element.toString(); 1963 } 1964 s ~= ")"; 1965 return s; 1966 } 1967 1968 override bool opEquals(Object o) 1969 { 1970 if (this is o) 1971 return true; 1972 1973 auto t = cast(const TypeInfo_Tuple)o; 1974 if (t && elements.length == t.elements.length) 1975 { 1976 for (size_t i = 0; i < elements.length; i++) 1977 { 1978 if (elements[i] != t.elements[i]) 1979 return false; 1980 } 1981 return true; 1982 } 1983 return false; 1984 } 1985 1986 override size_t getHash(scope const void* p) const 1987 { 1988 assert(0); 1989 } 1990 1991 override bool equals(in void* p1, in void* p2) const 1992 { 1993 assert(0); 1994 } 1995 1996 override int compare(in void* p1, in void* p2) const 1997 { 1998 assert(0); 1999 } 2000 2001 override @property size_t tsize() nothrow pure const 2002 { 2003 assert(0); 2004 } 2005 2006 override const(void)[] initializer() const @trusted 2007 { 2008 assert(0); 2009 } 2010 2011 override void swap(void* p1, void* p2) const 2012 { 2013 assert(0); 2014 } 2015 2016 override void destroy(void* p) const 2017 { 2018 assert(0); 2019 } 2020 2021 override void postblit(void* p) const 2022 { 2023 assert(0); 2024 } 2025 2026 override @property size_t talign() nothrow pure const 2027 { 2028 assert(0); 2029 } 2030 2031 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 2032 { 2033 assert(0); 2034 } 2035 } 2036 2037 class TypeInfo_Struct : TypeInfo 2038 { 2039 override string toString() const { return name; } 2040 2041 override size_t toHash() const 2042 { 2043 return hashOf(this.mangledName); 2044 } 2045 2046 override bool opEquals(Object o) 2047 { 2048 if (this is o) 2049 return true; 2050 auto s = cast(const TypeInfo_Struct)o; 2051 return s && this.mangledName == s.mangledName; 2052 } 2053 2054 override size_t getHash(scope const void* p) @trusted pure nothrow const 2055 { 2056 assert(p); 2057 if (xtoHash) 2058 { 2059 return (*xtoHash)(p); 2060 } 2061 else 2062 { 2063 return hashOf(p[0 .. initializer().length]); 2064 } 2065 } 2066 2067 override bool equals(in void* p1, in void* p2) @trusted pure nothrow const 2068 { 2069 import core.stdc.string : memcmp; 2070 2071 if (!p1 || !p2) 2072 return false; 2073 else if (xopEquals) 2074 { 2075 const dg = _memberFunc(p1, xopEquals); 2076 return dg.xopEquals(p2); 2077 } 2078 else if (p1 == p2) 2079 return true; 2080 else 2081 // BUG: relies on the GC not moving objects 2082 return memcmp(p1, p2, initializer().length) == 0; 2083 } 2084 2085 override int compare(in void* p1, in void* p2) @trusted pure nothrow const 2086 { 2087 import core.stdc.string : memcmp; 2088 2089 // Regard null references as always being "less than" 2090 if (p1 != p2) 2091 { 2092 if (p1) 2093 { 2094 if (!p2) 2095 return true; 2096 else if (xopCmp) 2097 { 2098 const dg = _memberFunc(p1, xopCmp); 2099 return dg.xopCmp(p2); 2100 } 2101 else 2102 // BUG: relies on the GC not moving objects 2103 return memcmp(p1, p2, initializer().length); 2104 } 2105 else 2106 return -1; 2107 } 2108 return 0; 2109 } 2110 2111 override @property size_t tsize() nothrow pure const 2112 { 2113 return initializer().length; 2114 } 2115 2116 override const(void)[] initializer() nothrow pure const @safe 2117 { 2118 return m_init; 2119 } 2120 2121 override @property uint flags() nothrow pure const { return m_flags; } 2122 2123 override @property size_t talign() nothrow pure const { return m_align; } 2124 2125 final override void destroy(void* p) const 2126 { 2127 if (xdtor) 2128 { 2129 if (m_flags & StructFlags.isDynamicType) 2130 (*xdtorti)(p, this); 2131 else 2132 (*xdtor)(p); 2133 } 2134 } 2135 2136 override void postblit(void* p) const 2137 { 2138 if (xpostblit) 2139 (*xpostblit)(p); 2140 } 2141 2142 string mangledName; 2143 2144 final @property string name() nothrow const @trusted 2145 { 2146 import core.demangle : demangleType; 2147 2148 if (mangledName is null) // e.g., opaque structs 2149 return null; 2150 2151 const key = cast(const void*) this; // faster lookup than TypeInfo_Struct, at the cost of potential duplicates per binary 2152 static string[typeof(key)] demangledNamesCache; // per thread 2153 2154 // not nothrow: 2155 //return demangledNamesCache.require(key, cast(string) demangleType(mangledName)); 2156 2157 if (auto pDemangled = key in demangledNamesCache) 2158 return *pDemangled; 2159 2160 const demangled = cast(string) demangleType(mangledName); 2161 demangledNamesCache[key] = demangled; 2162 return demangled; 2163 } 2164 2165 void[] m_init; // initializer; m_init.ptr == null if 0 initialize 2166 2167 @safe pure nothrow 2168 { 2169 size_t function(in void*) xtoHash; 2170 bool function(in void*, in void*) xopEquals; 2171 int function(in void*, in void*) xopCmp; 2172 string function(in void*) xtoString; 2173 2174 enum StructFlags : uint 2175 { 2176 hasPointers = 0x1, 2177 isDynamicType = 0x2, // built at runtime, needs type info in xdtor 2178 } 2179 StructFlags m_flags; 2180 } 2181 union 2182 { 2183 void function(void*) xdtor; 2184 void function(void*, const TypeInfo_Struct ti) xdtorti; 2185 } 2186 void function(void*) xpostblit; 2187 2188 uint m_align; 2189 2190 override @property immutable(void)* rtInfo() nothrow pure const @safe { return m_RTInfo; } 2191 2192 version (WithArgTypes) 2193 { 2194 override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 2195 { 2196 arg1 = m_arg1; 2197 arg2 = m_arg2; 2198 return 0; 2199 } 2200 TypeInfo m_arg1; 2201 TypeInfo m_arg2; 2202 } 2203 immutable(void)* m_RTInfo; // data for precise GC 2204 2205 // The xopEquals and xopCmp members are function pointers to member 2206 // functions, which is not guaranteed to share the same ABI, as it is not 2207 // known whether the `this` parameter is the first or second argument. 2208 // This wrapper is to convert it to a delegate which will always pass the 2209 // `this` parameter in the correct way. 2210 private struct _memberFunc 2211 { 2212 union 2213 { 2214 struct // delegate 2215 { 2216 const void* ptr; 2217 const void* funcptr; 2218 } 2219 @safe pure nothrow 2220 { 2221 bool delegate(in void*) xopEquals; 2222 int delegate(in void*) xopCmp; 2223 } 2224 } 2225 } 2226 } 2227 2228 class TypeInfo_Const : TypeInfo 2229 { 2230 override string toString() const 2231 { 2232 return cast(string) ("const(" ~ base.toString() ~ ")"); 2233 } 2234 2235 //override bool opEquals(Object o) { return base.opEquals(o); } 2236 override bool opEquals(Object o) 2237 { 2238 if (this is o) 2239 return true; 2240 2241 if (typeid(this) != typeid(o)) 2242 return false; 2243 2244 auto t = cast(TypeInfo_Const)o; 2245 return base.opEquals(t.base); 2246 } 2247 2248 override size_t getHash(scope const void *p) const { return base.getHash(p); } 2249 override bool equals(in void *p1, in void *p2) const { return base.equals(p1, p2); } 2250 override int compare(in void *p1, in void *p2) const { return base.compare(p1, p2); } 2251 override @property size_t tsize() nothrow pure const { return base.tsize; } 2252 override void swap(void *p1, void *p2) const { return base.swap(p1, p2); } 2253 2254 override @property inout(TypeInfo) next() nothrow pure inout { return base.next; } 2255 override @property uint flags() nothrow pure const { return base.flags; } 2256 2257 override const(void)[] initializer() nothrow pure const 2258 { 2259 return base.initializer(); 2260 } 2261 2262 override @property size_t talign() nothrow pure const { return base.talign; } 2263 2264 version (WithArgTypes) override int argTypes(out TypeInfo arg1, out TypeInfo arg2) 2265 { 2266 return base.argTypes(arg1, arg2); 2267 } 2268 2269 TypeInfo base; 2270 } 2271 2272 class TypeInfo_Invariant : TypeInfo_Const 2273 { 2274 override string toString() const 2275 { 2276 return cast(string) ("immutable(" ~ base.toString() ~ ")"); 2277 } 2278 } 2279 2280 class TypeInfo_Shared : TypeInfo_Const 2281 { 2282 override string toString() const 2283 { 2284 return cast(string) ("shared(" ~ base.toString() ~ ")"); 2285 } 2286 } 2287 2288 class TypeInfo_Inout : TypeInfo_Const 2289 { 2290 override string toString() const 2291 { 2292 return cast(string) ("inout(" ~ base.toString() ~ ")"); 2293 } 2294 } 2295 2296 2297 2298 // Contents of Moduleinfo._flags 2299 enum 2300 { 2301 MIctorstart = 0x1, // we've started constructing it 2302 MIctordone = 0x2, // finished construction 2303 MIstandalone = 0x4, // module ctor does not depend on other module 2304 // ctors being done first 2305 MItlsctor = 8, 2306 MItlsdtor = 0x10, 2307 MIctor = 0x20, 2308 MIdtor = 0x40, 2309 MIxgetMembers = 0x80, 2310 MIictor = 0x100, 2311 MIunitTest = 0x200, 2312 MIimportedModules = 0x400, 2313 MIlocalClasses = 0x800, 2314 MIname = 0x1000, 2315 } 2316 2317 /***************************************** 2318 * An instance of ModuleInfo is generated into the object file for each compiled module. 2319 * 2320 * It provides access to various aspects of the module. 2321 * It is not generated for betterC. 2322 */ 2323 struct ModuleInfo 2324 { 2325 uint _flags; // MIxxxx 2326 uint _index; // index into _moduleinfo_array[] 2327 2328 version (all) 2329 { 2330 deprecated("ModuleInfo cannot be copy-assigned because it is a variable-sized struct.") 2331 void opAssign(const scope ModuleInfo m) { _flags = m._flags; _index = m._index; } 2332 } 2333 else 2334 { 2335 @disable this(); 2336 } 2337 2338 const: 2339 private void* addrOf(int flag) return nothrow pure @nogc 2340 in 2341 { 2342 assert(flag >= MItlsctor && flag <= MIname); 2343 assert(!(flag & (flag - 1)) && !(flag & ~(flag - 1) << 1)); 2344 } 2345 do 2346 { 2347 import core.stdc.string : strlen; 2348 2349 void* p = cast(void*)&this + ModuleInfo.sizeof; 2350 2351 if (flags & MItlsctor) 2352 { 2353 if (flag == MItlsctor) return p; 2354 p += typeof(tlsctor).sizeof; 2355 } 2356 if (flags & MItlsdtor) 2357 { 2358 if (flag == MItlsdtor) return p; 2359 p += typeof(tlsdtor).sizeof; 2360 } 2361 if (flags & MIctor) 2362 { 2363 if (flag == MIctor) return p; 2364 p += typeof(ctor).sizeof; 2365 } 2366 if (flags & MIdtor) 2367 { 2368 if (flag == MIdtor) return p; 2369 p += typeof(dtor).sizeof; 2370 } 2371 if (flags & MIxgetMembers) 2372 { 2373 if (flag == MIxgetMembers) return p; 2374 p += typeof(xgetMembers).sizeof; 2375 } 2376 if (flags & MIictor) 2377 { 2378 if (flag == MIictor) return p; 2379 p += typeof(ictor).sizeof; 2380 } 2381 if (flags & MIunitTest) 2382 { 2383 if (flag == MIunitTest) return p; 2384 p += typeof(unitTest).sizeof; 2385 } 2386 if (flags & MIimportedModules) 2387 { 2388 if (flag == MIimportedModules) return p; 2389 p += size_t.sizeof + *cast(size_t*)p * typeof(importedModules[0]).sizeof; 2390 } 2391 if (flags & MIlocalClasses) 2392 { 2393 if (flag == MIlocalClasses) return p; 2394 p += size_t.sizeof + *cast(size_t*)p * typeof(localClasses[0]).sizeof; 2395 } 2396 if (true || flags & MIname) // always available for now 2397 { 2398 if (flag == MIname) return p; 2399 p += strlen(cast(immutable char*)p); 2400 } 2401 assert(0); 2402 } 2403 2404 @property uint index() nothrow pure @nogc { return _index; } 2405 2406 @property uint flags() nothrow pure @nogc { return _flags; } 2407 2408 /************************ 2409 * Returns: 2410 * module constructor for thread locals, `null` if there isn't one 2411 */ 2412 @property void function() tlsctor() nothrow pure @nogc 2413 { 2414 return flags & MItlsctor ? *cast(typeof(return)*)addrOf(MItlsctor) : null; 2415 } 2416 2417 /************************ 2418 * Returns: 2419 * module destructor for thread locals, `null` if there isn't one 2420 */ 2421 @property void function() tlsdtor() nothrow pure @nogc 2422 { 2423 return flags & MItlsdtor ? *cast(typeof(return)*)addrOf(MItlsdtor) : null; 2424 } 2425 2426 /***************************** 2427 * Returns: 2428 * address of a module's `const(MemberInfo)[] getMembers(string)` function, `null` if there isn't one 2429 */ 2430 @property void* xgetMembers() nothrow pure @nogc 2431 { 2432 return flags & MIxgetMembers ? *cast(typeof(return)*)addrOf(MIxgetMembers) : null; 2433 } 2434 2435 /************************ 2436 * Returns: 2437 * module constructor, `null` if there isn't one 2438 */ 2439 @property void function() ctor() nothrow pure @nogc 2440 { 2441 return flags & MIctor ? *cast(typeof(return)*)addrOf(MIctor) : null; 2442 } 2443 2444 /************************ 2445 * Returns: 2446 * module destructor, `null` if there isn't one 2447 */ 2448 @property void function() dtor() nothrow pure @nogc 2449 { 2450 return flags & MIdtor ? *cast(typeof(return)*)addrOf(MIdtor) : null; 2451 } 2452 2453 /************************ 2454 * Returns: 2455 * module order independent constructor, `null` if there isn't one 2456 */ 2457 @property void function() ictor() nothrow pure @nogc 2458 { 2459 return flags & MIictor ? *cast(typeof(return)*)addrOf(MIictor) : null; 2460 } 2461 2462 /************* 2463 * Returns: 2464 * address of function that runs the module's unittests, `null` if there isn't one 2465 */ 2466 @property void function() unitTest() nothrow pure @nogc 2467 { 2468 return flags & MIunitTest ? *cast(typeof(return)*)addrOf(MIunitTest) : null; 2469 } 2470 2471 /**************** 2472 * Returns: 2473 * array of pointers to the ModuleInfo's of modules imported by this one 2474 */ 2475 @property immutable(ModuleInfo*)[] importedModules() return nothrow pure @nogc 2476 { 2477 if (flags & MIimportedModules) 2478 { 2479 auto p = cast(size_t*)addrOf(MIimportedModules); 2480 return (cast(immutable(ModuleInfo*)*)(p + 1))[0 .. *p]; 2481 } 2482 return null; 2483 } 2484 2485 /**************** 2486 * Returns: 2487 * array of TypeInfo_Class references for classes defined in this module 2488 */ 2489 @property TypeInfo_Class[] localClasses() return nothrow pure @nogc 2490 { 2491 if (flags & MIlocalClasses) 2492 { 2493 auto p = cast(size_t*)addrOf(MIlocalClasses); 2494 return (cast(TypeInfo_Class*)(p + 1))[0 .. *p]; 2495 } 2496 return null; 2497 } 2498 2499 /******************** 2500 * Returns: 2501 * name of module, `null` if no name 2502 */ 2503 @property string name() return nothrow pure @nogc 2504 { 2505 import core.stdc.string : strlen; 2506 2507 auto p = cast(immutable char*) addrOf(MIname); 2508 return p[0 .. strlen(p)]; 2509 } 2510 2511 static int opApply(scope int delegate(ModuleInfo*) dg) 2512 { 2513 import core.internal.traits : externDFunc; 2514 alias moduleinfos_apply = externDFunc!("rt.minfo.moduleinfos_apply", 2515 int function(scope int delegate(immutable(ModuleInfo*)))); 2516 // Bugzilla 13084 - enforcing immutable ModuleInfo would break client code 2517 return moduleinfos_apply( 2518 (immutable(ModuleInfo*)m) => dg(cast(ModuleInfo*)m)); 2519 } 2520 } 2521 2522 2523 /////////////////////////////////////////////////////////////////////////////// 2524 // Throwable 2525 /////////////////////////////////////////////////////////////////////////////// 2526 2527 2528 /** 2529 * The base class of all thrown objects. 2530 * 2531 * All thrown objects must inherit from Throwable. Class $(D Exception), which 2532 * derives from this class, represents the category of thrown objects that are 2533 * safe to catch and handle. In principle, one should not catch Throwable 2534 * objects that are not derived from $(D Exception), as they represent 2535 * unrecoverable runtime errors. Certain runtime guarantees may fail to hold 2536 * when these errors are thrown, making it unsafe to continue execution after 2537 * catching them. 2538 */ 2539 class Throwable : Object 2540 { 2541 interface TraceInfo 2542 { 2543 int opApply(scope int delegate(ref const(char[]))) const; 2544 int opApply(scope int delegate(ref size_t, ref const(char[]))) const; 2545 string toString() const; 2546 } 2547 2548 string msg; /// A message describing the error. 2549 2550 /** 2551 * The _file name of the D source code corresponding with 2552 * where the error was thrown from. 2553 */ 2554 string file; 2555 /** 2556 * The _line number of the D source code corresponding with 2557 * where the error was thrown from. 2558 */ 2559 size_t line; 2560 2561 /** 2562 * The stack trace of where the error happened. This is an opaque object 2563 * that can either be converted to $(D string), or iterated over with $(D 2564 * foreach) to extract the items in the stack trace (as strings). 2565 */ 2566 TraceInfo info; 2567 2568 /** 2569 * A reference to the _next error in the list. This is used when a new 2570 * $(D Throwable) is thrown from inside a $(D catch) block. The originally 2571 * caught $(D Exception) will be chained to the new $(D Throwable) via this 2572 * field. 2573 */ 2574 private Throwable nextInChain; 2575 2576 private uint _refcount; // 0 : allocated by GC 2577 // 1 : allocated by _d_newThrowable() 2578 // 2.. : reference count + 1 2579 2580 /** 2581 * Returns: 2582 * A reference to the _next error in the list. This is used when a new 2583 * $(D Throwable) is thrown from inside a $(D catch) block. The originally 2584 * caught $(D Exception) will be chained to the new $(D Throwable) via this 2585 * field. 2586 */ 2587 @property inout(Throwable) next() @safe inout return scope pure nothrow @nogc { return nextInChain; } 2588 2589 /** 2590 * Replace next in chain with `tail`. 2591 * Use `chainTogether` instead if at all possible. 2592 */ 2593 @property void next(Throwable tail) @safe scope pure nothrow @nogc 2594 { 2595 // if (tail && tail._refcount) 2596 // ++tail._refcount; // increment the replacement *first* 2597 2598 // auto n = nextInChain; 2599 // nextInChain = null; // sever the tail before deleting it 2600 2601 // if (n && n._refcount) 2602 // _d_delThrowable(n); // now delete the old tail 2603 2604 // nextInChain = tail; // and set the new tail 2605 } 2606 2607 /** 2608 * Returns: 2609 * mutable reference to the reference count, which is 2610 * 0 - allocated by the GC, 1 - allocated by _d_newThrowable(), 2611 * and >=2 which is the reference count + 1 2612 */ 2613 @system @nogc final pure nothrow ref uint refcount() return scope { return _refcount; } 2614 2615 /** 2616 * Loop over the chain of Throwables. 2617 */ 2618 int opApply(scope int delegate(Throwable) dg) 2619 { 2620 // int result = 0; 2621 // for (Throwable t = this; t; t = t.nextInChain) 2622 // { 2623 // result = dg(t); 2624 // if (result) 2625 // break; 2626 // } 2627 // return result; 2628 return 0; 2629 } 2630 2631 /** 2632 * Append `e2` to chain of exceptions that starts with `e1`. 2633 * Params: 2634 * e1 = start of chain (can be null) 2635 * e2 = second part of chain (can be null) 2636 * Returns: 2637 * Throwable that is at the start of the chain; null if both `e1` and `e2` are null 2638 */ 2639 static @__future @system @nogc pure nothrow Throwable chainTogether(return scope Throwable e1, return scope Throwable e2) 2640 { 2641 // if (e2 && e2.refcount()) 2642 // ++e2.refcount(); 2643 // if (!e1) 2644 // return e2; 2645 // if (!e2) 2646 // return e1; 2647 // for (auto e = e1; 1; e = e.nextInChain) 2648 // { 2649 // if (!e.nextInChain) 2650 // { 2651 // e.nextInChain = e2; 2652 // break; 2653 // } 2654 // } 2655 return e1; 2656 } 2657 2658 @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null) 2659 { 2660 // this.msg = msg; 2661 // this.nextInChain = nextInChain; 2662 //this.info = _d_traceContext(); 2663 } 2664 2665 @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null) 2666 { 2667 // this(msg, nextInChain); 2668 // this.file = file; 2669 // this.line = line; 2670 //this.info = _d_traceContext(); 2671 } 2672 2673 @trusted nothrow ~this() 2674 { 2675 // if (nextInChain && nextInChain._refcount) 2676 // _d_delThrowable(nextInChain); 2677 } 2678 2679 /** 2680 * Get the message describing the error. 2681 * Base behavior is to return the `Throwable.msg` field. 2682 * Override to return some other error message. 2683 * 2684 * Returns: 2685 * Error message 2686 */ 2687 @__future const(char)[] message() const 2688 { 2689 return this.msg; 2690 } 2691 } 2692 2693 2694 /** 2695 * The base class of all errors that are safe to catch and handle. 2696 * 2697 * In principle, only thrown objects derived from this class are safe to catch 2698 * inside a $(D catch) block. Thrown objects not derived from Exception 2699 * represent runtime errors that should not be caught, as certain runtime 2700 * guarantees may not hold, making it unsafe to continue program execution. 2701 */ 2702 class Exception : Throwable 2703 { 2704 2705 /** 2706 * Creates a new instance of Exception. The nextInChain parameter is used 2707 * internally and should always be $(D null) when passed by user code. 2708 * This constructor does not automatically throw the newly-created 2709 * Exception; the $(D throw) statement should be used for that purpose. 2710 */ 2711 @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable nextInChain = null) 2712 { 2713 super(msg, file, line, nextInChain); 2714 } 2715 2716 @nogc @safe pure nothrow this(string msg, Throwable nextInChain, string file = __FILE__, size_t line = __LINE__) 2717 { 2718 super(msg, file, line, nextInChain); 2719 } 2720 } 2721 /+ 2722 /// 2723 @safe unittest 2724 { 2725 bool gotCaught; 2726 try 2727 { 2728 throw new Exception("msg"); 2729 } 2730 catch (Exception e) 2731 { 2732 gotCaught = true; 2733 assert(e.msg == "msg"); 2734 } 2735 assert(gotCaught); 2736 } 2737 2738 @system unittest 2739 { 2740 { 2741 auto e = new Exception("msg"); 2742 assert(e.file == __FILE__); 2743 assert(e.line == __LINE__ - 2); 2744 assert(e.nextInChain is null); 2745 assert(e.msg == "msg"); 2746 } 2747 2748 { 2749 auto e = new Exception("msg", new Exception("It's an Exception!"), "hello", 42); 2750 assert(e.file == "hello"); 2751 assert(e.line == 42); 2752 assert(e.nextInChain !is null); 2753 assert(e.msg == "msg"); 2754 } 2755 2756 { 2757 auto e = new Exception("msg", "hello", 42, new Exception("It's an Exception!")); 2758 assert(e.file == "hello"); 2759 assert(e.line == 42); 2760 assert(e.nextInChain !is null); 2761 assert(e.msg == "msg"); 2762 } 2763 2764 { 2765 auto e = new Exception("message"); 2766 assert(e.message == "message"); 2767 } 2768 } 2769 2770 +/ 2771 /** 2772 * The base class of all unrecoverable runtime errors. 2773 * 2774 * This represents the category of $(D Throwable) objects that are $(B not) 2775 * safe to catch and handle. In principle, one should not catch Error 2776 * objects, as they represent unrecoverable runtime errors. 2777 * Certain runtime guarantees may fail to hold when these errors are 2778 * thrown, making it unsafe to continue execution after catching them. 2779 */ 2780 class Error : Throwable 2781 { 2782 /** 2783 * Creates a new instance of Error. The nextInChain parameter is used 2784 * internally and should always be $(D null) when passed by user code. 2785 * This constructor does not automatically throw the newly-created 2786 * Error; the $(D throw) statement should be used for that purpose. 2787 */ 2788 @nogc @safe pure nothrow this(string msg, Throwable nextInChain = null) 2789 { 2790 super(msg, nextInChain); 2791 bypassedException = null; 2792 } 2793 2794 @nogc @safe pure nothrow this(string msg, string file, size_t line, Throwable nextInChain = null) 2795 { 2796 super(msg, file, line, nextInChain); 2797 bypassedException = null; 2798 } 2799 2800 /** The first $(D Exception) which was bypassed when this Error was thrown, 2801 or $(D null) if no $(D Exception)s were pending. */ 2802 Throwable bypassedException; 2803 } 2804 2805 2806 /// 2807 @system unittest 2808 { 2809 bool gotCaught; 2810 try 2811 { 2812 throw new Error("msg"); 2813 } 2814 catch (Error e) 2815 { 2816 gotCaught = true; 2817 assert(e.msg == "msg"); 2818 } 2819 assert(gotCaught); 2820 } 2821 2822 @safe unittest 2823 { 2824 { 2825 auto e = new Error("msg"); 2826 assert(e.file is null); 2827 assert(e.line == 0); 2828 assert(e.nextInChain is null); 2829 assert(e.msg == "msg"); 2830 assert(e.bypassedException is null); 2831 } 2832 2833 { 2834 auto e = new Error("msg", new Exception("It's an Exception!")); 2835 assert(e.file is null); 2836 assert(e.line == 0); 2837 assert(e.nextInChain !is null); 2838 assert(e.msg == "msg"); 2839 assert(e.bypassedException is null); 2840 } 2841 2842 { 2843 auto e = new Error("msg", "hello", 42, new Exception("It's an Exception!")); 2844 assert(e.file == "hello"); 2845 assert(e.line == 42); 2846 assert(e.nextInChain !is null); 2847 assert(e.msg == "msg"); 2848 assert(e.bypassedException is null); 2849 } 2850 } 2851 2852 extern (C) 2853 { 2854 // from druntime/src/rt/aaA.d 2855 2856 version (LDC) 2857 { 2858 /* The real type is (non-importable) `rt.aaA.Impl*`; 2859 * the compiler uses `void*` for its prototypes. 2860 */ 2861 private alias AA = void*; 2862 } 2863 else 2864 { 2865 private struct AA { void* impl; } 2866 } 2867 2868 // size_t _aaLen(in AA aa) pure nothrow @nogc; 2869 private void* _aaGetY(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey) pure nothrow; 2870 private void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey, out bool found) pure nothrow; 2871 // inout(void)* _aaGetRvalueX(inout AA aa, in TypeInfo keyti, in size_t valsz, in void* pkey); 2872 inout(void[]) _aaValues(inout AA aa, const size_t keysz, const size_t valsz, const TypeInfo tiValueArray) pure nothrow; 2873 inout(void[]) _aaKeys(inout AA aa, const size_t keysz, const TypeInfo tiKeyArray) pure nothrow; 2874 void* _aaRehash(AA* paa, const scope TypeInfo keyti) pure nothrow; 2875 void _aaClear(AA aa) pure nothrow; 2876 2877 // alias _dg_t = extern(D) int delegate(void*); 2878 // int _aaApply(AA aa, size_t keysize, _dg_t dg); 2879 2880 // alias _dg2_t = extern(D) int delegate(void*, void*); 2881 // int _aaApply2(AA aa, size_t keysize, _dg2_t dg); 2882 2883 private struct AARange { AA impl; size_t idx; } 2884 AARange _aaRange(AA aa) pure nothrow @nogc @safe; 2885 bool _aaRangeEmpty(AARange r) pure nothrow @nogc @safe; 2886 void* _aaRangeFrontKey(AARange r) pure nothrow @nogc @safe; 2887 void* _aaRangeFrontValue(AARange r) pure nothrow @nogc @safe; 2888 void _aaRangePopFront(ref AARange r) pure nothrow @nogc @safe; 2889 2890 int _aaEqual(scope const TypeInfo tiRaw, scope const AA aa1, scope const AA aa2); 2891 hash_t _aaGetHash(scope const AA* aa, scope const TypeInfo tiRaw) nothrow; 2892 2893 /* 2894 _d_assocarrayliteralTX marked as pure, because aaLiteral can be called from pure code. 2895 This is a typesystem hole, however this is existing hole. 2896 Early compiler didn't check purity of toHash or postblit functions, if key is a UDT thus 2897 copiler allowed to create AA literal with keys, which have impure unsafe toHash methods. 2898 */ 2899 void* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void[] keys, void[] values) pure; 2900 } 2901 2902 2903 void* aaLiteral(Key, Value)(Key[] keys, Value[] values) @trusted pure 2904 { 2905 return _d_assocarrayliteralTX(typeid(Value[Key]), *cast(void[]*)&keys, *cast(void[]*)&values); 2906 } 2907 2908 alias AssociativeArray(Key, Value) = Value[Key]; 2909 2910 /*********************************** 2911 * Removes all remaining keys and values from an associative array. 2912 * Params: 2913 * aa = The associative array. 2914 */ 2915 void clear(T : Value[Key], Value, Key)(T aa) 2916 { 2917 _aaClear(*cast(void **) &aa); 2918 } 2919 2920 /* ditto */ 2921 void clear(T : Value[Key], Value, Key)(T* aa) 2922 { 2923 _aaClear(*cast(void **) aa); 2924 } 2925 2926 /// 2927 @system unittest 2928 { 2929 auto aa = ["k1": 2]; 2930 aa.clear; 2931 assert("k1" !in aa); 2932 } 2933 2934 /*********************************** 2935 * Reorganizes the associative array in place so that lookups are more 2936 * efficient. 2937 * Params: 2938 * aa = The associative array. 2939 * Returns: 2940 * The rehashed associative array. 2941 */ 2942 T rehash(T : Value[Key], Value, Key)(T aa) 2943 { 2944 _aaRehash(cast(void**)&aa, typeid(Value[Key])); 2945 return aa; 2946 } 2947 2948 /* ditto */ 2949 T rehash(T : Value[Key], Value, Key)(T* aa) 2950 { 2951 _aaRehash(cast(void**)aa, typeid(Value[Key])); 2952 return *aa; 2953 } 2954 2955 /* ditto */ 2956 T rehash(T : shared Value[Key], Value, Key)(T aa) 2957 { 2958 _aaRehash(cast(void**)&aa, typeid(Value[Key])); 2959 return aa; 2960 } 2961 2962 /* ditto */ 2963 T rehash(T : shared Value[Key], Value, Key)(T* aa) 2964 { 2965 _aaRehash(cast(void**)aa, typeid(Value[Key])); 2966 return *aa; 2967 } 2968 2969 /*********************************** 2970 * Create a new associative array of the same size and copy the contents of the 2971 * associative array into it. 2972 * Params: 2973 * aa = The associative array. 2974 */ 2975 V[K] dup(T : V[K], K, V)(T aa) 2976 { 2977 //pragma(msg, "K = ", K, ", V = ", V); 2978 2979 // Bug10720 - check whether V is copyable 2980 static assert(is(typeof({ V v = aa[K.init]; })), 2981 "cannot call " ~ T.stringof ~ ".dup because " ~ V.stringof ~ " is not copyable"); 2982 2983 V[K] result; 2984 2985 //foreach (k, ref v; aa) 2986 // result[k] = v; // Bug13701 - won't work if V is not mutable 2987 2988 ref V duplicateElem(ref K k, ref const V v) @trusted pure nothrow 2989 { 2990 import core.stdc.string : memcpy; 2991 2992 void* pv = _aaGetY(cast(void**)&result, typeid(V[K]), V.sizeof, &k); 2993 memcpy(pv, &v, V.sizeof); 2994 return *cast(V*)pv; 2995 } 2996 2997 if (auto postblit = _getPostblit!V()) 2998 { 2999 foreach (k, ref v; aa) 3000 postblit(duplicateElem(k, v)); 3001 } 3002 else 3003 { 3004 foreach (k, ref v; aa) 3005 duplicateElem(k, v); 3006 } 3007 3008 return result; 3009 } 3010 3011 /* ditto */ 3012 V[K] dup(T : V[K], K, V)(T* aa) 3013 { 3014 return (*aa).dup; 3015 } 3016 3017 /// 3018 @safe unittest 3019 { 3020 auto aa = ["k1": 2]; 3021 auto a2 = aa.dup; 3022 aa["k2"] = 3; 3023 assert("k2" !in a2); 3024 } 3025 3026 // this should never be made public. 3027 private AARange _aaToRange(T: V[K], K, V)(ref T aa) pure nothrow @nogc @safe 3028 { 3029 // ensure we are dealing with a genuine AA. 3030 static if (is(const(V[K]) == const(T))) 3031 alias realAA = aa; 3032 else 3033 const(V[K]) realAA = aa; 3034 return _aaRange(() @trusted { return cast(void*)realAA; } ()); 3035 } 3036 3037 /// 3038 @safe unittest 3039 { 3040 auto dict = [1: 0, 2: 0]; 3041 int sum; 3042 foreach (v; dict.byKey) 3043 sum += v; 3044 3045 assert(sum == 3); 3046 } 3047 3048 /// 3049 @safe unittest 3050 { 3051 auto dict = ["k1": 1, "k2": 2]; 3052 int sum; 3053 foreach (v; dict.byValue) 3054 sum += v; 3055 3056 assert(sum == 3); 3057 } 3058 3059 // Constraints for aa update. Delegates, Functions or Functors (classes that 3060 // provide opCall) are allowed. See unittest for an example. 3061 private 3062 { 3063 template isCreateOperation(C, V) 3064 { 3065 static if (is(C : V delegate()) || is(C : V function())) 3066 enum bool isCreateOperation = true; 3067 else static if (isCreateOperation!(typeof(&C.opCall), V)) 3068 enum bool isCreateOperation = true; 3069 else 3070 enum bool isCreateOperation = false; 3071 } 3072 3073 template isUpdateOperation(U, V) 3074 { 3075 static if (is(U : V delegate(ref V)) || is(U : V function(ref V))) 3076 enum bool isUpdateOperation = true; 3077 else static if (isUpdateOperation!(typeof(&U.opCall), V)) 3078 enum bool isUpdateOperation = true; 3079 else 3080 enum bool isUpdateOperation = false; 3081 } 3082 } 3083 3084 // Tests whether T can be @safe-ly copied. Use a union to exclude destructor from the test. 3085 private enum bool isSafeCopyable(T) = is(typeof(() @safe { union U { T x; } T *x; auto u = U(*x); })); 3086 3087 /+ 3088 private void _destructRecurse(E, size_t n)(ref E[n] arr) 3089 { 3090 import core.internal.traits : hasElaborateDestructor; 3091 3092 static if (hasElaborateDestructor!E) 3093 { 3094 foreach_reverse (ref elem; arr) 3095 _destructRecurse(elem); 3096 } 3097 } 3098 +/ 3099 // Public and explicitly undocumented 3100 void _postblitRecurse(S)(ref S s) 3101 if (is(S == struct)) 3102 { 3103 static if (__traits(hasMember, S, "__xpostblit") && 3104 // Bugzilla 14746: Check that it's the exact member of S. 3105 __traits(isSame, S, __traits(parent, s.__xpostblit))) 3106 s.__xpostblit(); 3107 } 3108 3109 // Ditto 3110 void _postblitRecurse(E, size_t n)(ref E[n] arr) 3111 { 3112 import core.internal.traits : hasElaborateCopyConstructor; 3113 3114 static if (hasElaborateCopyConstructor!E) 3115 { 3116 size_t i; 3117 scope(failure) 3118 { 3119 for (; i != 0; --i) 3120 { 3121 _destructRecurse(arr[i - 1]); // What to do if this throws? 3122 } 3123 } 3124 3125 for (i = 0; i < arr.length; ++i) 3126 _postblitRecurse(arr[i]); 3127 } 3128 } 3129 3130 // Test destruction/postblit order 3131 @safe nothrow pure unittest 3132 { 3133 string[] order; 3134 3135 struct InnerTop 3136 { 3137 ~this() @safe nothrow pure 3138 { 3139 order ~= "destroy inner top"; 3140 } 3141 3142 this(this) @safe nothrow pure 3143 { 3144 order ~= "copy inner top"; 3145 } 3146 } 3147 3148 struct InnerMiddle {} 3149 3150 version (none) // https://issues.dlang.org/show_bug.cgi?id=14242 3151 struct InnerElement 3152 { 3153 static char counter = '1'; 3154 3155 ~this() @safe nothrow pure 3156 { 3157 order ~= "destroy inner element #" ~ counter++; 3158 } 3159 3160 this(this) @safe nothrow pure 3161 { 3162 order ~= "copy inner element #" ~ counter++; 3163 } 3164 } 3165 3166 struct InnerBottom 3167 { 3168 ~this() @safe nothrow pure 3169 { 3170 order ~= "destroy inner bottom"; 3171 } 3172 3173 this(this) @safe nothrow pure 3174 { 3175 order ~= "copy inner bottom"; 3176 } 3177 } 3178 3179 struct S 3180 { 3181 char[] s; 3182 InnerTop top; 3183 InnerMiddle middle; 3184 version (none) InnerElement[3] array; // https://issues.dlang.org/show_bug.cgi?id=14242 3185 int a; 3186 InnerBottom bottom; 3187 ~this() @safe nothrow pure { order ~= "destroy outer"; } 3188 this(this) @safe nothrow pure { order ~= "copy outer"; } 3189 } 3190 3191 string[] destructRecurseOrder; 3192 { 3193 S s; 3194 _destructRecurse(s); 3195 destructRecurseOrder = order; 3196 order = null; 3197 } 3198 3199 assert(order.length); 3200 assert(destructRecurseOrder == order); 3201 order = null; 3202 3203 S s; 3204 _postblitRecurse(s); 3205 assert(order.length); 3206 auto postblitRecurseOrder = order; 3207 order = null; 3208 S s2 = s; 3209 assert(order.length); 3210 assert(postblitRecurseOrder == order); 3211 } 3212 3213 // Test static struct 3214 nothrow @safe @nogc unittest 3215 { 3216 static int i = 0; 3217 static struct S { ~this() nothrow @safe @nogc { i = 42; } } 3218 S s; 3219 _destructRecurse(s); 3220 assert(i == 42); 3221 } 3222 3223 @safe unittest 3224 { 3225 // Bugzilla 14746 3226 static struct HasDtor 3227 { 3228 ~this() { assert(0); } 3229 } 3230 static struct Owner 3231 { 3232 HasDtor* ptr; 3233 alias ptr this; 3234 } 3235 3236 Owner o; 3237 assert(o.ptr is null); 3238 destroy(o); // must not reach in HasDtor.__dtor() 3239 } 3240 3241 @safe unittest 3242 { 3243 // Bugzilla 14746 3244 static struct HasPostblit 3245 { 3246 this(this) { assert(0); } 3247 } 3248 static struct Owner 3249 { 3250 HasPostblit* ptr; 3251 alias ptr this; 3252 } 3253 3254 Owner o; 3255 assert(o.ptr is null); 3256 _postblitRecurse(o); // must not reach in HasPostblit.__postblit() 3257 } 3258 3259 // Test handling of fixed-length arrays 3260 // Separate from first test because of https://issues.dlang.org/show_bug.cgi?id=14242 3261 @safe unittest 3262 { 3263 string[] order; 3264 3265 struct S 3266 { 3267 char id; 3268 3269 this(this) 3270 { 3271 order ~= "copy #" ~ id; 3272 } 3273 3274 ~this() 3275 { 3276 order ~= "destroy #" ~ id; 3277 } 3278 } 3279 3280 string[] destructRecurseOrder; 3281 { 3282 S[3] arr = [S('1'), S('2'), S('3')]; 3283 _destructRecurse(arr); 3284 destructRecurseOrder = order; 3285 order = null; 3286 } 3287 assert(order.length); 3288 assert(destructRecurseOrder == order); 3289 order = null; 3290 3291 S[3] arr = [S('1'), S('2'), S('3')]; 3292 _postblitRecurse(arr); 3293 assert(order.length); 3294 auto postblitRecurseOrder = order; 3295 order = null; 3296 3297 auto arrCopy = arr; 3298 assert(order.length); 3299 assert(postblitRecurseOrder == order); 3300 } 3301 3302 // Test handling of failed postblit 3303 // Not nothrow or @safe because of https://issues.dlang.org/show_bug.cgi?id=14242 3304 /+ nothrow @safe +/ unittest 3305 { 3306 static class FailedPostblitException : Exception { this() nothrow @safe { super(null); } } 3307 static string[] order; 3308 static struct Inner 3309 { 3310 char id; 3311 3312 @safe: 3313 this(this) 3314 { 3315 order ~= "copy inner #" ~ id; 3316 if (id == '2') 3317 throw new FailedPostblitException(); 3318 } 3319 3320 ~this() nothrow 3321 { 3322 order ~= "destroy inner #" ~ id; 3323 } 3324 } 3325 3326 static struct Outer 3327 { 3328 Inner inner1, inner2, inner3; 3329 3330 nothrow @safe: 3331 this(char first, char second, char third) 3332 { 3333 inner1 = Inner(first); 3334 inner2 = Inner(second); 3335 inner3 = Inner(third); 3336 } 3337 3338 this(this) 3339 { 3340 order ~= "copy outer"; 3341 } 3342 3343 ~this() 3344 { 3345 order ~= "destroy outer"; 3346 } 3347 } 3348 3349 auto outer = Outer('1', '2', '3'); 3350 3351 try _postblitRecurse(outer); 3352 catch (FailedPostblitException) {} 3353 catch (Exception) assert(false); 3354 3355 auto postblitRecurseOrder = order; 3356 order = null; 3357 3358 try auto copy = outer; 3359 catch (FailedPostblitException) {} 3360 catch (Exception) assert(false); 3361 3362 assert(postblitRecurseOrder == order); 3363 order = null; 3364 3365 Outer[3] arr = [Outer('1', '1', '1'), Outer('1', '2', '3'), Outer('3', '3', '3')]; 3366 3367 try _postblitRecurse(arr); 3368 catch (FailedPostblitException) {} 3369 catch (Exception) assert(false); 3370 3371 postblitRecurseOrder = order; 3372 order = null; 3373 3374 try auto arrCopy = arr; 3375 catch (FailedPostblitException) {} 3376 catch (Exception) assert(false); 3377 3378 assert(postblitRecurseOrder == order); 3379 } 3380 3381 private 3382 { 3383 extern (C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow; 3384 extern (C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* arrptr) pure nothrow; 3385 } 3386 3387 /** 3388 * (Property) Gets the current _capacity of a slice. The _capacity is the size 3389 * that the slice can grow to before the underlying array must be 3390 * reallocated or extended. 3391 * 3392 * If an append must reallocate a slice with no possibility of extension, then 3393 * `0` is returned. This happens when the slice references a static array, or 3394 * if another slice references elements past the end of the current slice. 3395 * 3396 * Note: The _capacity of a slice may be impacted by operations on other slices. 3397 */ 3398 @property size_t capacity(T)(T[] arr) pure nothrow @trusted 3399 { 3400 return _d_arraysetcapacity(typeid(T[]), 0, cast(void[]*)&arr); 3401 } 3402 3403 /// 3404 @safe unittest 3405 { 3406 //Static array slice: no capacity 3407 int[4] sarray = [1, 2, 3, 4]; 3408 int[] slice = sarray[]; 3409 assert(sarray.capacity == 0); 3410 //Appending to slice will reallocate to a new array 3411 slice ~= 5; 3412 assert(slice.capacity >= 5); 3413 3414 //Dynamic array slices 3415 int[] a = [1, 2, 3, 4]; 3416 int[] b = a[1 .. $]; 3417 int[] c = a[1 .. $ - 1]; 3418 debug(SENTINEL) {} else // non-zero capacity very much depends on the array and GC implementation 3419 { 3420 assert(a.capacity != 0); 3421 assert(a.capacity == b.capacity + 1); //both a and b share the same tail 3422 } 3423 assert(c.capacity == 0); //an append to c must relocate c. 3424 } 3425 3426 /** 3427 * Reserves capacity for a slice. The capacity is the size 3428 * that the slice can grow to before the underlying array must be 3429 * reallocated or extended. 3430 * 3431 * Returns: The new capacity of the array (which may be larger than 3432 * the requested capacity). 3433 */ 3434 size_t reserve(T)(ref T[] arr, size_t newcapacity) pure nothrow @trusted 3435 { 3436 if (__ctfe) 3437 return newcapacity; 3438 else 3439 return _d_arraysetcapacity(typeid(T[]), newcapacity, cast(void[]*)&arr); 3440 } 3441 3442 /// 3443 @safe unittest 3444 { 3445 //Static array slice: no capacity. Reserve relocates. 3446 int[4] sarray = [1, 2, 3, 4]; 3447 int[] slice = sarray[]; 3448 auto u = slice.reserve(8); 3449 assert(u >= 8); 3450 assert(&sarray[0] !is &slice[0]); 3451 assert(slice.capacity == u); 3452 3453 //Dynamic array slices 3454 int[] a = [1, 2, 3, 4]; 3455 a.reserve(8); //prepare a for appending 4 more items 3456 auto p = &a[0]; 3457 u = a.capacity; 3458 a ~= [5, 6, 7, 8]; 3459 assert(p == &a[0]); //a should not have been reallocated 3460 assert(u == a.capacity); //a should not have been extended 3461 } 3462 3463 // https://issues.dlang.org/show_bug.cgi?id=12330, reserve() at CTFE time 3464 @safe unittest 3465 { 3466 int[] foo() { 3467 int[] result; 3468 auto a = result.reserve = 5; 3469 assert(a == 5); 3470 return result; 3471 } 3472 enum r = foo(); 3473 } 3474 3475 // Issue 6646: should be possible to use array.reserve from SafeD. 3476 @safe unittest 3477 { 3478 int[] a; 3479 a.reserve(10); 3480 } 3481 3482 /** 3483 * Assume that it is safe to append to this array. Appends made to this array 3484 * after calling this function may append in place, even if the array was a 3485 * slice of a larger array to begin with. 3486 * 3487 * Use this only when it is certain there are no elements in use beyond the 3488 * array in the memory block. If there are, those elements will be 3489 * overwritten by appending to this array. 3490 * 3491 * Warning: Calling this function, and then using references to data located after the 3492 * given array results in undefined behavior. 3493 * 3494 * Returns: 3495 * The input is returned. 3496 */ 3497 auto ref inout(T[]) assumeSafeAppend(T)(auto ref inout(T[]) arr) nothrow @system 3498 { 3499 _d_arrayshrinkfit(typeid(T[]), *(cast(void[]*)&arr)); 3500 return arr; 3501 } 3502 3503 /// 3504 @system unittest 3505 { 3506 int[] a = [1, 2, 3, 4]; 3507 3508 // Without assumeSafeAppend. Appending relocates. 3509 int[] b = a [0 .. 3]; 3510 b ~= 5; 3511 assert(a.ptr != b.ptr); 3512 3513 debug(SENTINEL) {} else 3514 { 3515 // With assumeSafeAppend. Appending overwrites. 3516 int[] c = a [0 .. 3]; 3517 c.assumeSafeAppend() ~= 5; 3518 assert(a.ptr == c.ptr); 3519 } 3520 } 3521 3522 @system unittest 3523 { 3524 int[] arr; 3525 auto newcap = arr.reserve(2000); 3526 assert(newcap >= 2000); 3527 assert(newcap == arr.capacity); 3528 auto ptr = arr.ptr; 3529 foreach (i; 0..2000) 3530 arr ~= i; 3531 assert(ptr == arr.ptr); 3532 arr = arr[0..1]; 3533 arr.assumeSafeAppend(); 3534 arr ~= 5; 3535 assert(ptr == arr.ptr); 3536 } 3537 3538 @system unittest 3539 { 3540 int[] arr = [1, 2, 3]; 3541 void foo(ref int[] i) 3542 { 3543 i ~= 5; 3544 } 3545 arr = arr[0 .. 2]; 3546 foo(assumeSafeAppend(arr)); //pass by ref 3547 assert(arr[]==[1, 2, 5]); 3548 arr = arr[0 .. 1].assumeSafeAppend(); //pass by value 3549 } 3550 3551 // https://issues.dlang.org/show_bug.cgi?id=10574 3552 @system unittest 3553 { 3554 int[] a; 3555 immutable(int[]) b; 3556 auto a2 = &assumeSafeAppend(a); 3557 auto b2 = &assumeSafeAppend(b); 3558 auto a3 = assumeSafeAppend(a[]); 3559 auto b3 = assumeSafeAppend(b[]); 3560 assert(is(typeof(*a2) == int[])); 3561 assert(is(typeof(*b2) == immutable(int[]))); 3562 assert(is(typeof(a3) == int[])); 3563 assert(is(typeof(b3) == immutable(int[]))); 3564 } 3565 3566 version (none) 3567 { 3568 // enforce() copied from Phobos std.contracts for destroy(), left out until 3569 // we decide whether to use it. 3570 3571 3572 T _enforce(T, string file = __FILE__, int line = __LINE__) 3573 (T value, lazy const(char)[] msg = null) 3574 { 3575 if (!value) bailOut(file, line, msg); 3576 return value; 3577 } 3578 3579 T _enforce(T, string file = __FILE__, int line = __LINE__) 3580 (T value, scope void delegate() dg) 3581 { 3582 if (!value) dg(); 3583 return value; 3584 } 3585 3586 T _enforce(T)(T value, lazy Exception ex) 3587 { 3588 if (!value) throw ex(); 3589 return value; 3590 } 3591 3592 private void _bailOut(string file, int line, in char[] msg) 3593 { 3594 char[21] buf = void; 3595 throw new Exception(cast(string)(file ~ "(" ~ ulongToString(buf[], line) ~ "): " ~ (msg ? msg : "Enforcement failed"))); 3596 } 3597 } 3598 3599 3600 public import core.internal.hash : hashOf; 3601 /+ 3602 /// 3603 @system unittest 3604 { 3605 class MyObject 3606 { 3607 size_t myMegaHash() const @safe pure nothrow 3608 { 3609 return 42; 3610 } 3611 } 3612 struct Test 3613 { 3614 int a; 3615 string b; 3616 MyObject c; 3617 size_t toHash() const pure nothrow 3618 { 3619 size_t hash = a.hashOf(); 3620 hash = b.hashOf(hash); 3621 size_t h1 = c.myMegaHash(); 3622 hash = h1.hashOf(hash); //Mix two hash values 3623 return hash; 3624 } 3625 } 3626 } 3627 +/ 3628 bool _xopEquals(in void*, in void*) 3629 { 3630 assert(false, "TypeInfo.equals is not implemented"); 3631 } 3632 3633 bool _xopCmp(in void*, in void*) 3634 { 3635 assert(false, "TypeInfo.compare is not implemented"); 3636 } 3637 3638 void __ctfeWrite(scope const(char)[] s) @nogc @safe pure nothrow {} 3639 3640 /****************************************** 3641 * Create RTInfo for type T 3642 */ 3643 3644 template RTInfoImpl(size_t[] pointerBitmap) 3645 { 3646 immutable size_t[pointerBitmap.length] RTInfoImpl = pointerBitmap[]; 3647 } 3648 3649 template NoPointersBitmapPayload(size_t N) 3650 { 3651 enum size_t[N] NoPointersBitmapPayload = 0; 3652 } 3653 3654 template RTInfo(T) 3655 { 3656 enum pointerBitmap = __traits(getPointerBitmap, T); 3657 static if (pointerBitmap[1 .. $] == NoPointersBitmapPayload!(pointerBitmap.length - 1)) 3658 enum RTInfo = rtinfoNoPointers; 3659 else 3660 enum RTInfo = RTInfoImpl!(pointerBitmap).ptr; 3661 } 3662 3663 3664 /** 3665 * shortcuts for the precise GC, also generated by the compiler 3666 * used instead of the actual pointer bitmap 3667 */ 3668 enum immutable(void)* rtinfoNoPointers = null; 3669 enum immutable(void)* rtinfoHasPointers = cast(void*)1; 3670 3671 3672 // Helper functions 3673 3674 private inout(TypeInfo) getElement(return scope inout TypeInfo value) @trusted pure nothrow 3675 { 3676 TypeInfo element = cast() value; 3677 for (;;) 3678 { 3679 if (auto qualified = cast(TypeInfo_Const) element) 3680 element = qualified.base; 3681 else if (auto redefined = cast(TypeInfo_Enum) element) 3682 element = redefined.base; 3683 else if (auto staticArray = cast(TypeInfo_StaticArray) element) 3684 element = staticArray.value; 3685 else if (auto vector = cast(TypeInfo_Vector) element) 3686 element = vector.base; 3687 else 3688 break; 3689 } 3690 return cast(inout) element; 3691 } 3692 3693 // Compiler hook into the runtime implementation of array (vector) operations. 3694 template _arrayOp(Args...) 3695 { 3696 import core.internal.array.operations; 3697 alias _arrayOp = arrayOp!Args; 3698 } 3699 3700 /* 3701 * Support for switch statements switching on strings. 3702 * Params: 3703 * caseLabels = sorted array of strings generated by compiler. Note the 3704 strings are sorted by length first, and then lexicographically. 3705 * condition = string to look up in table 3706 * Returns: 3707 * index of match in caseLabels, a negative integer if not found 3708 */ 3709 int __switch(T, caseLabels...)(/*in*/ const scope T[] condition) pure nothrow @safe @nogc 3710 { 3711 // This closes recursion for other cases. 3712 static if (caseLabels.length == 0) 3713 { 3714 return int.min; 3715 } 3716 else static if (caseLabels.length == 1) 3717 { 3718 return __cmp(condition, caseLabels[0]) == 0 ? 0 : int.min; 3719 } 3720 // To be adjusted after measurements 3721 // Compile-time inlined binary search. 3722 else 3723 { 3724 int r = void; 3725 enum mid = cast(int)caseLabels.length / 2; 3726 if (condition.length == caseLabels[mid].length) 3727 { 3728 r = __cmp(condition, caseLabels[mid]); 3729 if (r == 0) return mid; 3730 } 3731 else 3732 { 3733 // Equivalent to (but faster than) condition.length > caseLabels[$ / 2].length ? 1 : -1 3734 r = ((condition.length > caseLabels[mid].length) << 1) - 1; 3735 } 3736 3737 if (r < 0) 3738 { 3739 // Search the left side 3740 return __switch!(T, caseLabels[0 .. mid])(condition); 3741 } 3742 else 3743 { 3744 // Search the right side 3745 return __switch!(T, caseLabels[mid + 1 .. $])(condition) + mid + 1; 3746 } 3747 } 3748 } 3749 3750 // binary search in sorted string cases, also see `__switch`. 3751 private int __switchSearch(T)(/*in*/ const scope T[][] cases, /*in*/ const scope T[] condition) pure nothrow @safe @nogc 3752 { 3753 size_t low = 0; 3754 size_t high = cases.length; 3755 3756 do 3757 { 3758 auto mid = (low + high) / 2; 3759 int r = void; 3760 if (condition.length == cases[mid].length) 3761 { 3762 r = __cmp(condition, cases[mid]); 3763 if (r == 0) return cast(int) mid; 3764 } 3765 else 3766 { 3767 // Generates better code than "expr ? 1 : -1" on dmd and gdc, same with ldc 3768 r = ((condition.length > cases[mid].length) << 1) - 1; 3769 } 3770 3771 if (r > 0) low = mid + 1; 3772 else high = mid; 3773 } 3774 while (low < high); 3775 3776 // Not found 3777 return -1; 3778 } 3779 /+ 3780 @system unittest 3781 { 3782 static void testSwitch(T)() 3783 { 3784 switch (cast(T[]) "c") 3785 { 3786 case "coo": 3787 default: 3788 break; 3789 } 3790 3791 static int bug5381(immutable(T)[] s) 3792 { 3793 switch (s) 3794 { 3795 case "unittest": return 1; 3796 case "D_Version2": return 2; 3797 case "nonenone": return 3; 3798 case "none": return 4; 3799 case "all": return 5; 3800 default: return 6; 3801 } 3802 } 3803 3804 int rc = bug5381("unittest"); 3805 assert(rc == 1); 3806 3807 rc = bug5381("D_Version2"); 3808 assert(rc == 2); 3809 3810 rc = bug5381("nonenone"); 3811 assert(rc == 3); 3812 3813 rc = bug5381("none"); 3814 assert(rc == 4); 3815 3816 rc = bug5381("all"); 3817 assert(rc == 5); 3818 3819 rc = bug5381("nonerandom"); 3820 assert(rc == 6); 3821 3822 static int binarySearch(immutable(T)[] s) 3823 { 3824 switch (s) 3825 { 3826 static foreach (i; 0 .. 16) 3827 case i.stringof: return i; 3828 default: return -1; 3829 } 3830 } 3831 static foreach (i; 0 .. 16) 3832 assert(binarySearch(i.stringof) == i); 3833 assert(binarySearch("") == -1); 3834 assert(binarySearch("sth.") == -1); 3835 assert(binarySearch(null) == -1); 3836 3837 static int bug16739(immutable(T)[] s) 3838 { 3839 switch (s) 3840 { 3841 case "\u0100": return 1; 3842 case "a": return 2; 3843 default: return 3; 3844 } 3845 } 3846 assert(bug16739("\u0100") == 1); 3847 assert(bug16739("a") == 2); 3848 assert(bug16739("foo") == 3); 3849 } 3850 testSwitch!char; 3851 testSwitch!wchar; 3852 testSwitch!dchar; 3853 } 3854 +/ 3855 // Compiler lowers final switch default case to this (which is a runtime error) 3856 // Old implementation is in core/exception.d 3857 void __switch_error()(string file = __FILE__, size_t line = __LINE__) 3858 { 3859 import core.exception : __switch_errorT; 3860 __switch_errorT(file, line); 3861 } 3862 3863 3864 /// Provide the .dup array property. 3865 @property auto dup(T)(T[] a) 3866 if (!is(const(T) : T)) 3867 { 3868 import core.internal.traits : Unconst; 3869 import core.internal.array.duplication : _dup; 3870 static assert(is(T : Unconst!T), "Cannot implicitly convert type "~T.stringof~ 3871 " to "~Unconst!T.stringof~" in dup."); 3872 3873 return _dup!(T, Unconst!T)(a); 3874 } 3875 3876 3877 /// ditto 3878 // const overload to support implicit conversion to immutable (unique result, see DIP29) 3879 @property T[] dup(T)(const(T)[] a) 3880 if (is(const(T) : T)) 3881 { 3882 import core.internal.array.duplication : _dup; 3883 return _dup!(const(T), T)(a); 3884 } 3885 3886 3887 /// Provide the .idup array property. 3888 @property immutable(T)[] idup(T)(T[] a) 3889 { 3890 import core.internal.array.duplication : _dup; 3891 static assert(is(T : immutable(T)), "Cannot implicitly convert type "~T.stringof~ 3892 " to immutable in idup."); 3893 return _dup!(T, immutable(T))(a); 3894 } 3895 3896 3897 /// ditto 3898 @property immutable(T)[] idup(T:void)(const(T)[] a) 3899 { 3900 return a.dup; 3901 } 3902 3903 /// 3904 @safe unittest 3905 { 3906 char[] arr = ['a', 'b', 'c']; 3907 string s = arr.idup; 3908 arr[0] = '.'; 3909 assert(s == "abc"); 3910 } 3911 3912 private extern (C) void[] _d_newarrayU(const TypeInfo ti, size_t length) pure nothrow; 3913 3914 3915 /************** 3916 * Get the postblit for type T. 3917 * Returns: 3918 * null if no postblit is necessary 3919 * function pointer for struct postblits 3920 * delegate for class postblits 3921 */ 3922 private auto _getPostblit(T)() @trusted pure nothrow @nogc 3923 { 3924 // infer static postblit type, run postblit if any 3925 static if (is(T == struct)) 3926 { 3927 import core.internal.traits : Unqual; 3928 // use typeid(Unqual!T) here to skip TypeInfo_Const/Shared/... 3929 alias _PostBlitType = typeof(function (ref T t){ T a = t; }); 3930 return cast(_PostBlitType)typeid(Unqual!T).xpostblit; 3931 } 3932 else if ((&typeid(T).postblit).funcptr !is &TypeInfo.postblit) 3933 { 3934 alias _PostBlitType = typeof(delegate (ref T t){ T a = t; }); 3935 return cast(_PostBlitType)&typeid(T).postblit; 3936 } 3937 else 3938 return null; 3939 } 3940 3941 private void _doPostblit(T)(T[] arr) 3942 { 3943 // infer static postblit type, run postblit if any 3944 if (auto postblit = _getPostblit!T()) 3945 { 3946 foreach (ref elem; arr) 3947 postblit(elem); 3948 } 3949 } 3950 3951 @safe unittest 3952 { 3953 static struct S1 { int* p; } 3954 static struct S2 { @disable this(); } 3955 static struct S3 { @disable this(this); } 3956 3957 int dg1() pure nothrow @safe 3958 { 3959 { 3960 char[] m; 3961 string i; 3962 m = m.dup; 3963 i = i.idup; 3964 m = i.dup; 3965 i = m.idup; 3966 } 3967 { 3968 S1[] m; 3969 immutable(S1)[] i; 3970 m = m.dup; 3971 i = i.idup; 3972 static assert(!is(typeof(m.idup))); 3973 static assert(!is(typeof(i.dup))); 3974 } 3975 { 3976 S3[] m; 3977 immutable(S3)[] i; 3978 static assert(!is(typeof(m.dup))); 3979 static assert(!is(typeof(i.idup))); 3980 } 3981 { 3982 shared(S1)[] m; 3983 m = m.dup; 3984 static assert(!is(typeof(m.idup))); 3985 } 3986 { 3987 int[] a = (inout(int)) { inout(const(int))[] a; return a.dup; }(0); 3988 } 3989 return 1; 3990 } 3991 3992 int dg2() pure nothrow @safe 3993 { 3994 { 3995 S2[] m = [S2.init, S2.init]; 3996 immutable(S2)[] i = [S2.init, S2.init]; 3997 m = m.dup; 3998 m = i.dup; 3999 i = m.idup; 4000 i = i.idup; 4001 } 4002 return 2; 4003 } 4004 4005 enum a = dg1(); 4006 enum b = dg2(); 4007 assert(dg1() == a); 4008 assert(dg2() == b); 4009 } 4010 4011 @system unittest 4012 { 4013 static struct Sunpure { this(this) @safe nothrow {} } 4014 static struct Sthrow { this(this) @safe pure {} } 4015 static struct Sunsafe { this(this) @system pure nothrow {} } 4016 4017 static assert( __traits(compiles, () { [].dup!Sunpure; })); 4018 static assert(!__traits(compiles, () pure { [].dup!Sunpure; })); 4019 static assert( __traits(compiles, () { [].dup!Sthrow; })); 4020 static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; })); 4021 static assert( __traits(compiles, () { [].dup!Sunsafe; })); 4022 static assert(!__traits(compiles, () @safe { [].dup!Sunsafe; })); 4023 4024 static assert( __traits(compiles, () { [].idup!Sunpure; })); 4025 static assert(!__traits(compiles, () pure { [].idup!Sunpure; })); 4026 static assert( __traits(compiles, () { [].idup!Sthrow; })); 4027 static assert(!__traits(compiles, () nothrow { [].idup!Sthrow; })); 4028 static assert( __traits(compiles, () { [].idup!Sunsafe; })); 4029 static assert(!__traits(compiles, () @safe { [].idup!Sunsafe; })); 4030 } 4031 4032 @safe unittest 4033 { 4034 static int*[] pureFoo() pure { return null; } 4035 { char[] s; immutable x = s.dup; } 4036 { immutable x = (cast(int*[])null).dup; } 4037 { immutable x = pureFoo(); } 4038 { immutable x = pureFoo().dup; } 4039 } 4040 4041 @safe unittest 4042 { 4043 auto a = [1, 2, 3]; 4044 auto b = a.dup; 4045 debug(SENTINEL) {} else 4046 assert(b.capacity >= 3); 4047 } 4048 4049 @system unittest 4050 { 4051 // Bugzilla 12580 4052 void[] m = [0]; 4053 shared(void)[] s = [cast(shared)1]; 4054 immutable(void)[] i = [cast(immutable)2]; 4055 4056 s = s.dup; 4057 static assert(is(typeof(s.dup) == shared(void)[])); 4058 4059 m = i.dup; 4060 i = m.dup; 4061 i = i.idup; 4062 i = m.idup; 4063 i = s.idup; 4064 i = s.dup; 4065 static assert(!__traits(compiles, m = s.dup)); 4066 } 4067 4068 @safe unittest 4069 { 4070 // Bugzilla 13809 4071 static struct S 4072 { 4073 this(this) {} 4074 ~this() {} 4075 } 4076 4077 S[] arr; 4078 auto a = arr.dup; 4079 } 4080 4081 @system unittest 4082 { 4083 // Bugzilla 16504 4084 static struct S 4085 { 4086 __gshared int* gp; 4087 int* p; 4088 // postblit and hence .dup could escape 4089 this(this) { gp = p; } 4090 } 4091 4092 int p; 4093 scope S[1] arr = [S(&p)]; 4094 auto a = arr.dup; // dup does escape 4095 } 4096 4097 // compiler frontend lowers dynamic array comparison to this 4098 bool __ArrayEq(T1, T2)(scope T1[] a, scope T2[] b) 4099 { 4100 if (a.length != b.length) 4101 return false; 4102 foreach (size_t i; 0 .. a.length) 4103 { 4104 if (a[i] != b[i]) 4105 return false; 4106 } 4107 return true; 4108 } 4109 4110 // compiler frontend lowers struct array postblitting to this 4111 void __ArrayPostblit(T)(scope T[] a) 4112 { 4113 foreach (ref T e; a) 4114 e.__xpostblit(); 4115 } 4116 4117 // compiler frontend lowers dynamic array deconstruction to this 4118 void __ArrayDtor(T)(scope T[] a) 4119 { 4120 foreach_reverse (ref T e; a) 4121 e.__xdtor(); 4122 } 4123 4124 /** 4125 Used by `__ArrayCast` to emit a descriptive error message. 4126 4127 It is a template so it can be used by `__ArrayCast` in -betterC 4128 builds. It is separate from `__ArrayCast` to minimize code 4129 bloat. 4130 4131 Params: 4132 fromType = name of the type being cast from 4133 fromSize = total size in bytes of the array being cast from 4134 toType = name of the type being cast o 4135 toSize = total size in bytes of the array being cast to 4136 */ 4137 private void onArrayCastError()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted 4138 { 4139 import core.internal.string : unsignedToTempString; 4140 4141 const(char)[][9] msgComponents = 4142 [ 4143 "An array of size " 4144 , unsignedToTempString(fromSize) 4145 , " does not align on an array of size " 4146 , unsignedToTempString(toSize) 4147 , ", so `" 4148 , fromType 4149 , "` cannot be cast to `" 4150 , toType 4151 , "`" 4152 ]; 4153 4154 // convert discontiguous `msgComponents` to contiguous string on the stack 4155 enum msgLength = 2048; 4156 char[msgLength] msg; 4157 4158 size_t index = 0; 4159 foreach (m; msgComponents) 4160 { 4161 foreach (c; m) 4162 { 4163 msg[index++] = c; 4164 if (index >= (msgLength - 1)) 4165 break; 4166 } 4167 4168 if (index >= (msgLength - 1)) 4169 break; 4170 } 4171 msg[index] = '\0'; // null-termination 4172 4173 // first argument must evaluate to `false` at compile-time to maintain memory safety in release builds 4174 assert(false, msg); 4175 } 4176 4177 /** 4178 The compiler lowers expressions of `cast(TTo[])TFrom[]` to 4179 this implementation. 4180 4181 Params: 4182 from = the array to reinterpret-cast 4183 4184 Returns: 4185 `from` reinterpreted as `TTo[]` 4186 */ 4187 TTo[] __ArrayCast(TFrom, TTo)(TFrom[] from) @nogc pure @trusted 4188 { 4189 const fromSize = from.length * TFrom.sizeof; 4190 const toLength = fromSize / TTo.sizeof; 4191 4192 if ((fromSize % TTo.sizeof) != 0) 4193 { 4194 onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof); 4195 } 4196 4197 struct Array 4198 { 4199 size_t length; 4200 void* ptr; 4201 } 4202 auto a = cast(Array*)&from; 4203 a.length = toLength; // jam new length 4204 return *cast(TTo[]*)a; 4205 } 4206 4207 @safe @nogc pure nothrow unittest 4208 { 4209 byte[int.sizeof * 3] b = cast(byte) 0xab; 4210 int[] i; 4211 short[] s; 4212 4213 i = __ArrayCast!(byte, int)(b); 4214 assert(i.length == 3); 4215 foreach (v; i) 4216 assert(v == cast(int) 0xabab_abab); 4217 4218 s = __ArrayCast!(byte, short)(b); 4219 assert(s.length == 6); 4220 foreach (v; s) 4221 assert(v == cast(short) 0xabab); 4222 4223 s = __ArrayCast!(int, short)(i); 4224 assert(s.length == 6); 4225 foreach (v; s) 4226 assert(v == cast(short) 0xabab); 4227 } 4228 4229 export extern(C) void _D9invariant12_d_invariantFC6ObjectZv(Object o) 4230 { ClassInfo c; 4231 4232 //printf("__d_invariant(%p)\n", o); 4233 4234 // BUG: needs to be filename/line of caller, not library routine 4235 assert(o !is null); // just do null check, not invariant check 4236 4237 c = typeid(o); 4238 do 4239 { 4240 if (c.classInvariant) 4241 { 4242 (*c.classInvariant)(o); 4243 } 4244 c = c.base; 4245 } while (c); 4246 } 4247 4248 public import core.internal.array.appending : _d_arrayappendT; 4249 4250 public import core.internal.array.appending : _d_arrayappendcTX; 4251 //public import core.internal.array.comparison : __cmp; 4252 public import core.internal.array.equality : __equals; 4253 //public import core.internal.array.casting: __ArrayCast; 4254 public import core.internal.array.concatenation : _d_arraycatnTX; 4255 public import core.internal.array.construction : _d_arrayctor; 4256 public import core.internal.array.construction : _d_arraysetctor; 4257 public import core.internal.array.construction : _d_newarrayT; 4258 public import core.internal.array.arrayassign : _d_arrayassign_l; 4259 public import core.internal.array.arrayassign : _d_arrayassign_r; 4260 public import core.internal.array.arrayassign : _d_arraysetassign; 4261 public import core.internal.array.capacity: _d_arraysetlengthTImpl; 4262 4263 //public import core.internal.dassert: _d_assert_fail; 4264 4265 //public import core.internal.destruction: __ArrayDtor; 4266 4267 //public import core.internal.postblit: __ArrayPostblit; 4268 4269 //public import core.internal.switch_: __switch; 4270 //public import core.internal.switch_: __switch_error; 4271 4272 public import core.lifetime : _d_delstructImpl; 4273 public import core.lifetime : _d_newThrowable; 4274 public import core.lifetime : _d_newclassT; 4275 public import core.lifetime : _d_newclassTTrace; 4276 public import core.lifetime : _d_newitemT; 4277 4278 // Used in Exception Handling LSDA tables to 'wrap' C++ type info 4279 // so it can be distinguished from D TypeInfo 4280 class __cpp_type_info_ptr 4281 { 4282 void* ptr; // opaque pointer to C++ RTTI type info 4283 } 4284 4285 // Compiler hook into the runtime implementation of array (vector) operations. 4286 template _arrayOp(Args...) 4287 { 4288 import core.internal.array.operations; 4289 alias _arrayOp = arrayOp!Args; 4290 } 4291 4292 public import core.builtins : __ctfeWrite; 4293 4294 /** 4295 4296 Provides an "inline import", i.e. an `import` that is only available for a 4297 limited lookup. For example: 4298 4299 --- 4300 void fun(imported!"std.stdio".File input) 4301 { 4302 ... use File from std.stdio normally ... 4303 } 4304 --- 4305 4306 There is no need to import `std.stdio` at top level, so `fun` carries its own 4307 dependencies. The same approach can be used for template constraints: 4308 4309 --- 4310 void fun(T)(imported!"std.stdio".File input, T value) 4311 if (imported!"std.traits".isIntegral!T) 4312 { 4313 ... 4314 } 4315 --- 4316 4317 An inline import may be used in conjunction with the `with` statement as well. 4318 Inside the scope controlled by `with`, all symbols in the imported module are 4319 made available: 4320 4321 --- 4322 void fun() 4323 { 4324 with (imported!"std.datetime") 4325 with (imported!"std.stdio") 4326 { 4327 Clock.currTime.writeln; 4328 } 4329 } 4330 --- 4331 4332 The advantages of inline imports over top-level uses of the `import` declaration 4333 are the following: 4334 4335 $(UL 4336 $(LI The `imported` template specifies dependencies at declaration level, not at 4337 module level. This allows reasoning about the dependency cost of declarations in 4338 separation instead of aggregated at module level.) 4339 $(LI Declarations using `imported` are easier to move around because they don't 4340 require top-level context, making for simpler and quicker refactorings.) 4341 $(LI Declarations using `imported` scale better with templates. This is because 4342 templates that are not instantiated do not have their parameters and constraints 4343 instantiated, so additional modules are not imported without necessity. This 4344 makes the cost of unused templates negligible. Dependencies are pulled on a need 4345 basis depending on the declarations used by client code.) 4346 ) 4347 4348 The use of `imported` also has drawbacks: 4349 4350 $(UL 4351 $(LI If most declarations in a module need the same imports, then factoring them 4352 at top level, outside the declarations, is simpler than repeating them.) 4353 $(LI Traditional dependency-tracking tools such as make and other build systems 4354 assume file-level dependencies and need special tooling (such as rdmd) in order 4355 to work efficiently.) 4356 $(LI Dependencies at the top of a module are easier to inspect quickly than 4357 dependencies spread throughout the module.) 4358 ) 4359 4360 See_Also: The $(HTTP forum.dlang.org/post/tzqzmqhankrkbrfsrmbo@forum.dlang.org, 4361 forum discussion) that led to the creation of the `imported` facility. Credit is 4362 due to Daniel Nielsen and Dominikus Dittes Scherkl. 4363 4364 */ 4365 template imported(string moduleName) 4366 { 4367 mixin("import imported = " ~ moduleName ~ ";"); 4368 }