1 /** 2 * Put initializers and objects created from CTFE into a `dt_t` data structure 3 * so the backend puts them into the data segment. 4 * 5 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/todt.d, _todt.d) 9 * Documentation: https://dlang.org/phobos/dmd_todt.html 10 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/todt.d 11 */ 12 13 module dmd.todt; 14 15 import core.stdc.stdio; 16 import core.stdc.string; 17 18 import dmd.root.array; 19 import dmd.root.rmem; 20 21 import dmd.aggregate; 22 import dmd.arraytypes; 23 import dmd.backend.type; 24 import dmd.complex; 25 import dmd.ctfeexpr; 26 import dmd.declaration; 27 import dmd.dclass; 28 import dmd.denum; 29 import dmd.dstruct; 30 import dmd.dsymbol; 31 import dmd.dtemplate; 32 import dmd.errors; 33 import dmd.expression; 34 import dmd.func; 35 import dmd.globals; 36 import dmd.init; 37 import dmd.mtype; 38 import dmd.target; 39 import dmd.tokens; 40 import dmd.tocsym; 41 import dmd.toobj; 42 import dmd.typesem; 43 import dmd.typinf; 44 import dmd.visitor; 45 46 import dmd.backend.cc; 47 import dmd.backend.dt; 48 49 alias toSymbol = dmd.tocsym.toSymbol; 50 alias toSymbol = dmd.glue.toSymbol; 51 52 /* A dt_t is a simple structure representing data to be added 53 * to the data segment of the output object file. As such, 54 * it is a list of initialized bytes, 0 data, and offsets from 55 * other symbols. 56 * Each D symbol and type can be converted into a dt_t so it can 57 * be written to the data segment. 58 */ 59 60 alias Dts = Array!(dt_t*); 61 62 /* ================================================================ */ 63 64 extern (C++) void Initializer_toDt(Initializer init, ref DtBuilder dtb) 65 { 66 void visitError(ErrorInitializer) 67 { 68 assert(0); 69 } 70 71 void visitVoid(VoidInitializer vi) 72 { 73 /* Void initializers are set to 0, just because we need something 74 * to set them to in the static data segment. 75 */ 76 dtb.nzeros(cast(uint)vi.type.size()); 77 } 78 79 void visitStruct(StructInitializer si) 80 { 81 //printf("StructInitializer.toDt('%s')\n", si.toChars()); 82 assert(0); 83 } 84 85 void visitArray(ArrayInitializer ai) 86 { 87 //printf("ArrayInitializer.toDt('%s')\n", ai.toChars()); 88 Type tb = ai.type.toBasetype(); 89 if (tb.ty == Tvector) 90 tb = (cast(TypeVector)tb).basetype; 91 92 Type tn = tb.nextOf().toBasetype(); 93 94 //printf("\tdim = %d\n", ai.dim); 95 Dts dts; 96 dts.setDim(ai.dim); 97 dts.zero(); 98 99 uint size = cast(uint)tn.size(); 100 101 uint length = 0; 102 foreach (i, idx; ai.index) 103 { 104 if (idx) 105 length = cast(uint)idx.toInteger(); 106 //printf("\tindex[%d] = %p, length = %u, dim = %u\n", i, idx, length, ai.dim); 107 108 assert(length < ai.dim); 109 auto dtb = DtBuilder(0); 110 Initializer_toDt(ai.value[i], dtb); 111 if (dts[length]) 112 error(ai.loc, "duplicate initializations for index `%d`", length); 113 dts[length] = dtb.finish(); 114 length++; 115 } 116 117 Expression edefault = tb.nextOf().defaultInit(Loc.initial); 118 119 const n = tn.numberOfElems(ai.loc); 120 121 dt_t* dtdefault = null; 122 123 auto dtbarray = DtBuilder(0); 124 foreach (dt; dts) 125 { 126 if (dt) 127 dtbarray.cat(dt); 128 else 129 { 130 if (!dtdefault) 131 { 132 auto dtb = DtBuilder(0); 133 Expression_toDt(edefault, dtb); 134 dtdefault = dtb.finish(); 135 } 136 dtbarray.repeat(dtdefault, n); 137 } 138 } 139 switch (tb.ty) 140 { 141 case Tsarray: 142 { 143 TypeSArray ta = cast(TypeSArray)tb; 144 size_t tadim = cast(size_t)ta.dim.toInteger(); 145 if (ai.dim < tadim) 146 { 147 if (edefault.isBool(false)) 148 { 149 // pad out end of array 150 dtbarray.nzeros(cast(uint)(size * (tadim - ai.dim))); 151 } 152 else 153 { 154 if (!dtdefault) 155 { 156 auto dtb = DtBuilder(0); 157 Expression_toDt(edefault, dtb); 158 dtdefault = dtb.finish(); 159 } 160 161 const m = n * (tadim - ai.dim); 162 assert(m <= uint.max); 163 dtbarray.repeat(dtdefault, cast(uint)m); 164 } 165 } 166 else if (ai.dim > tadim) 167 { 168 error(ai.loc, "too many initializers, %u, for array[%llu]", ai.dim, cast(ulong) tadim); 169 } 170 dtb.cat(dtbarray); 171 break; 172 } 173 174 case Tpointer: 175 case Tarray: 176 { 177 if (tb.ty == Tarray) 178 dtb.size(ai.dim); 179 Symbol* s = dtb.dtoff(dtbarray.finish(), 0); 180 if (tn.isMutable()) 181 foreach (i; 0 .. ai.dim) 182 write_pointers(tn, s, size * cast(int)i); 183 break; 184 } 185 186 default: 187 assert(0); 188 } 189 dt_free(dtdefault); 190 } 191 192 void visitExp(ExpInitializer ei) 193 { 194 //printf("ExpInitializer.toDt() %s\n", ei.exp.toChars()); 195 ei.exp = ei.exp.optimize(WANTvalue); 196 Expression_toDt(ei.exp, dtb); 197 } 198 199 final switch (init.kind) 200 { 201 case InitKind.void_: return visitVoid (cast( VoidInitializer)init); 202 case InitKind.error: return visitError (cast( ErrorInitializer)init); 203 case InitKind.struct_: return visitStruct(cast(StructInitializer)init); 204 case InitKind.array: return visitArray (cast( ArrayInitializer)init); 205 case InitKind.exp: return visitExp (cast( ExpInitializer)init); 206 } 207 } 208 209 /* ================================================================ */ 210 211 extern (C++) void Expression_toDt(Expression e, ref DtBuilder dtb) 212 { 213 void nonConstExpError(Expression e) 214 { 215 version (none) 216 { 217 printf("Expression.toDt() %d\n", e.op); 218 } 219 e.error("non-constant expression `%s`", e.toChars()); 220 dtb.nzeros(1); 221 } 222 223 void visitCast(CastExp e) 224 { 225 version (none) 226 { 227 printf("CastExp.toDt() %d from %s to %s\n", e.op, e.e1.type.toChars(), e.type.toChars()); 228 } 229 if (e.e1.type.ty == Tclass) 230 { 231 if (auto toc = e.type.isTypeClass()) 232 { 233 if (auto toi = toc.sym.isInterfaceDeclaration()) // casting from class to interface 234 { 235 auto cre1 = e.e1.isClassReferenceExp(); 236 ClassDeclaration from = cre1.originalClass(); 237 int off = 0; 238 const isbase = toi.isBaseOf(from, &off); 239 assert(isbase); 240 ClassReferenceExp_toDt(cre1, dtb, off); 241 } 242 else //casting from class to class 243 { 244 Expression_toDt(e.e1, dtb); 245 } 246 return; 247 } 248 } 249 nonConstExpError(e); 250 } 251 252 void visitAddr(AddrExp e) 253 { 254 version (none) 255 { 256 printf("AddrExp.toDt() %d\n", e.op); 257 } 258 if (auto sl = e.e1.isStructLiteralExp()) 259 { 260 Symbol* s = toSymbol(sl); 261 dtb.xoff(s, 0); 262 if (sl.type.isMutable()) 263 write_pointers(sl.type, s, 0); 264 return; 265 } 266 nonConstExpError(e); 267 } 268 269 void visitInteger(IntegerExp e) 270 { 271 //printf("IntegerExp.toDt() %d\n", e.op); 272 const sz = cast(uint)e.type.size(); 273 if (auto value = e.getInteger()) 274 dtb.nbytes(sz, cast(char*)&value); 275 else 276 dtb.nzeros(sz); 277 } 278 279 void visitReal(RealExp e) 280 { 281 //printf("RealExp.toDt(%Lg)\n", e.value); 282 switch (e.type.toBasetype().ty) 283 { 284 case Tfloat32: 285 case Timaginary32: 286 { 287 auto fvalue = cast(float)e.value; 288 dtb.nbytes(4, cast(char*)&fvalue); 289 break; 290 } 291 292 case Tfloat64: 293 case Timaginary64: 294 { 295 auto dvalue = cast(double)e.value; 296 dtb.nbytes(8, cast(char*)&dvalue); 297 break; 298 } 299 300 case Tfloat80: 301 case Timaginary80: 302 { 303 auto evalue = e.value; 304 dtb.nbytes(target.realsize - target.realpad, cast(char*)&evalue); 305 dtb.nzeros(target.realpad); 306 break; 307 } 308 309 default: 310 printf("%s, e.type=%s\n", e.toChars(), e.type.toChars()); 311 assert(0); 312 } 313 } 314 315 void visitComplex(ComplexExp e) 316 { 317 //printf("ComplexExp.toDt() '%s'\n", e.toChars()); 318 switch (e.type.toBasetype().ty) 319 { 320 case Tcomplex32: 321 { 322 auto fvalue = cast(float)creall(e.value); 323 dtb.nbytes(4, cast(char*)&fvalue); 324 fvalue = cast(float)cimagl(e.value); 325 dtb.nbytes(4, cast(char*)&fvalue); 326 break; 327 } 328 329 case Tcomplex64: 330 { 331 auto dvalue = cast(double)creall(e.value); 332 dtb.nbytes(8, cast(char*)&dvalue); 333 dvalue = cast(double)cimagl(e.value); 334 dtb.nbytes(8, cast(char*)&dvalue); 335 break; 336 } 337 338 case Tcomplex80: 339 { 340 auto evalue = creall(e.value); 341 dtb.nbytes(target.realsize - target.realpad, cast(char*)&evalue); 342 dtb.nzeros(target.realpad); 343 evalue = cimagl(e.value); 344 dtb.nbytes(target.realsize - target.realpad, cast(char*)&evalue); 345 dtb.nzeros(target.realpad); 346 break; 347 } 348 349 default: 350 assert(0); 351 } 352 } 353 354 void visitNull(NullExp e) 355 { 356 assert(e.type); 357 dtb.nzeros(cast(uint)e.type.size()); 358 } 359 360 void visitString(StringExp e) 361 { 362 //printf("StringExp.toDt() '%s', type = %s\n", e.toChars(), e.type.toChars()); 363 Type t = e.type.toBasetype(); 364 365 // BUG: should implement some form of static string pooling 366 const n = cast(int)e.numberOfCodeUnits(); 367 const(char)* p; 368 char* q; 369 if (e.sz == 1) 370 p = e.peekString().ptr; 371 else 372 { 373 q = cast(char*)mem.xmalloc(n * e.sz); 374 e.writeTo(q, false); 375 p = q; 376 } 377 378 switch (t.ty) 379 { 380 case Tarray: 381 dtb.size(n); 382 goto case Tpointer; 383 384 case Tpointer: 385 if (e.sz == 1) 386 { 387 import dmd.e2ir : toStringSymbol; 388 import dmd.glue : totym; 389 Symbol* s = toStringSymbol(p, n, e.sz); 390 dtb.xoff(s, 0); 391 } 392 else 393 { 394 ubyte pow2 = e.sz == 4 ? 2 : 1; 395 dtb.abytes(0, n * e.sz, p, cast(uint)e.sz, pow2); 396 } 397 break; 398 399 case Tsarray: 400 { 401 auto tsa = t.isTypeSArray(); 402 403 dtb.nbytes(n * e.sz, p); 404 if (tsa.dim) 405 { 406 dinteger_t dim = tsa.dim.toInteger(); 407 if (n < dim) 408 { 409 // Pad remainder with 0 410 dtb.nzeros(cast(uint)((dim - n) * tsa.next.size())); 411 } 412 } 413 break; 414 } 415 416 default: 417 printf("StringExp.toDt(type = %s)\n", e.type.toChars()); 418 assert(0); 419 } 420 mem.xfree(q); 421 } 422 423 void visitArrayLiteral(ArrayLiteralExp e) 424 { 425 //printf("ArrayLiteralExp.toDt() '%s', type = %s\n", e.toChars(), e.type.toChars()); 426 427 auto dtbarray = DtBuilder(0); 428 foreach (i; 0 .. e.elements.dim) 429 { 430 Expression_toDt(e[i], dtbarray); 431 } 432 433 Type t = e.type.toBasetype(); 434 switch (t.ty) 435 { 436 case Tsarray: 437 dtb.cat(dtbarray); 438 break; 439 440 case Tarray: 441 dtb.size(e.elements.dim); 442 goto case Tpointer; 443 444 case Tpointer: 445 { 446 if (auto d = dtbarray.finish()) 447 dtb.dtoff(d, 0); 448 else 449 dtb.size(0); 450 451 break; 452 } 453 454 default: 455 assert(0); 456 } 457 } 458 459 void visitStructLiteral(StructLiteralExp sle) 460 { 461 //printf("StructLiteralExp.toDt() %s, ctfe = %d\n", sle.toChars(), sle.ownedByCtfe); 462 assert(sle.sd.nonHiddenFields() <= sle.elements.dim); 463 membersToDt(sle.sd, dtb, sle.elements, 0, null); 464 } 465 466 void visitSymOff(SymOffExp e) 467 { 468 //printf("SymOffExp.toDt('%s')\n", e.var.toChars()); 469 assert(e.var); 470 if (!(e.var.isDataseg() || e.var.isCodeseg()) || 471 e.var.needThis() || 472 e.var.isThreadlocal()) 473 { 474 return nonConstExpError(e); 475 } 476 dtb.xoff(toSymbol(e.var), cast(uint)e.offset); 477 } 478 479 void visitVar(VarExp e) 480 { 481 //printf("VarExp.toDt() %d\n", e.op); 482 483 if (auto v = e.var.isVarDeclaration()) 484 { 485 if ((v.isConst() || v.isImmutable()) && 486 e.type.toBasetype().ty != Tsarray && v._init) 487 { 488 e.error("recursive reference `%s`", e.toChars()); 489 return; 490 } 491 v.inuse++; 492 Initializer_toDt(v._init, dtb); 493 v.inuse--; 494 return; 495 } 496 497 if (auto sd = e.var.isSymbolDeclaration()) 498 if (sd.dsym) 499 { 500 StructDeclaration_toDt(sd.dsym, dtb); 501 return; 502 } 503 504 return nonConstExpError(e); 505 } 506 507 void visitFunc(FuncExp e) 508 { 509 //printf("FuncExp.toDt() %d\n", e.op); 510 if (e.fd.tok == TOK.reserved && e.type.ty == Tpointer) 511 { 512 // change to non-nested 513 e.fd.tok = TOK.function_; 514 e.fd.vthis = null; 515 } 516 Symbol *s = toSymbol(e.fd); 517 toObjFile(e.fd, false); 518 if (e.fd.tok == TOK.delegate_) 519 dtb.size(0); 520 dtb.xoff(s, 0); 521 } 522 523 void visitVector(VectorExp e) 524 { 525 //printf("VectorExp.toDt() %s\n", e.toChars()); 526 foreach (i; 0 .. e.dim) 527 { 528 Expression elem; 529 if (auto ale = e.e1.isArrayLiteralExp()) 530 elem = ale[i]; 531 else 532 elem = e.e1; 533 Expression_toDt(elem, dtb); 534 } 535 } 536 537 void visitClassReference(ClassReferenceExp e) 538 { 539 auto to = e.type.toBasetype().isTypeClass().sym.isInterfaceDeclaration(); 540 541 if (to) //Static typeof this literal is an interface. We must add offset to symbol 542 { 543 ClassDeclaration from = e.originalClass(); 544 int off = 0; 545 const isbase = to.isBaseOf(from, &off); 546 assert(isbase); 547 ClassReferenceExp_toDt(e, dtb, off); 548 } 549 else 550 ClassReferenceExp_toDt(e, dtb, 0); 551 } 552 553 void visitTypeid(TypeidExp e) 554 { 555 if (Type t = isType(e.obj)) 556 { 557 genTypeInfo(e.loc, t, null); 558 Symbol *s = toSymbol(t.vtinfo); 559 dtb.xoff(s, 0); 560 return; 561 } 562 assert(0); 563 } 564 565 switch (e.op) 566 { 567 default: return nonConstExpError(e); 568 case TOK.cast_: return visitCast (e.isCastExp()); 569 case TOK.address: return visitAddr (e.isAddrExp()); 570 case TOK.int64: return visitInteger (e.isIntegerExp()); 571 case TOK.float64: return visitReal (e.isRealExp()); 572 case TOK.complex80: return visitComplex (e.isComplexExp()); 573 case TOK.null_: return visitNull (e.isNullExp()); 574 case TOK.string_: return visitString (e.isStringExp()); 575 case TOK.arrayLiteral: return visitArrayLiteral (e.isArrayLiteralExp()); 576 case TOK.structLiteral: return visitStructLiteral (e.isStructLiteralExp()); 577 case TOK.symbolOffset: return visitSymOff (e.isSymOffExp()); 578 case TOK.variable: return visitVar (e.isVarExp()); 579 case TOK.function_: return visitFunc (e.isFuncExp()); 580 case TOK.vector: return visitVector (e.isVectorExp()); 581 case TOK.classReference: return visitClassReference(e.isClassReferenceExp()); 582 case TOK.typeid_: return visitTypeid (e.isTypeidExp()); 583 } 584 } 585 586 /* ================================================================= */ 587 588 // Generate the data for the static initializer. 589 590 extern (C++) void ClassDeclaration_toDt(ClassDeclaration cd, ref DtBuilder dtb) 591 { 592 //printf("ClassDeclaration.toDt(this = '%s')\n", cd.toChars()); 593 594 membersToDt(cd, dtb, null, 0, cd); 595 596 //printf("-ClassDeclaration.toDt(this = '%s')\n", cd.toChars()); 597 } 598 599 extern (C++) void StructDeclaration_toDt(StructDeclaration sd, ref DtBuilder dtb) 600 { 601 //printf("+StructDeclaration.toDt(), this='%s'\n", sd.toChars()); 602 membersToDt(sd, dtb, null, 0, null); 603 604 //printf("-StructDeclaration.toDt(), this='%s'\n", sd.toChars()); 605 } 606 607 /****************************** 608 * Generate data for instance of __cpp_type_info_ptr that refers 609 * to the C++ RTTI symbol for cd. 610 * Params: 611 * cd = C++ class 612 * dtb = data table builder 613 */ 614 extern (C++) void cpp_type_info_ptr_toDt(ClassDeclaration cd, ref DtBuilder dtb) 615 { 616 //printf("cpp_type_info_ptr_toDt(this = '%s')\n", cd.toChars()); 617 assert(cd.isCPPclass()); 618 619 // Put in first two members, the vtbl[] and the monitor 620 dtb.xoff(toVtblSymbol(ClassDeclaration.cpp_type_info_ptr), 0); 621 if (ClassDeclaration.cpp_type_info_ptr.hasMonitor()) 622 dtb.size(0); // monitor 623 624 // Create symbol for C++ type info 625 Symbol *s = toSymbolCppTypeInfo(cd); 626 627 // Put in address of cd's C++ type info 628 dtb.xoff(s, 0); 629 630 //printf("-cpp_type_info_ptr_toDt(this = '%s')\n", cd.toChars()); 631 } 632 633 /**************************************************** 634 * Put out initializers of ad.fields[]. 635 * Although this is consistent with the elements[] version, we 636 * have to use this optimized version to reduce memory footprint. 637 * Params: 638 * ad = aggregate with members 639 * pdt = tail of initializer list to start appending initialized data to 640 * elements = values to use as initializers, null means use default initializers 641 * firstFieldIndex = starting place is elements[firstFieldIndex] 642 * concreteType = structs: null, classes: most derived class 643 * ppb = pointer that moves through BaseClass[] from most derived class 644 * Returns: 645 * updated tail of dt_t list 646 */ 647 648 private void membersToDt(AggregateDeclaration ad, ref DtBuilder dtb, 649 Expressions* elements, size_t firstFieldIndex, 650 ClassDeclaration concreteType, 651 BaseClass*** ppb = null) 652 { 653 //printf("membersToDt(ad = '%s', concrete = '%s', ppb = %p)\n", ad.toChars(), concreteType ? concreteType.toChars() : "null", ppb); 654 ClassDeclaration cd = ad.isClassDeclaration(); 655 version (none) 656 { 657 printf(" interfaces.length = %d\n", cast(int)cd.interfaces.length); 658 foreach (i, b; cd.vtblInterfaces[]) 659 { 660 printf(" vbtblInterfaces[%d] b = %p, b.sym = %s\n", cast(int)i, b, b.sym.toChars()); 661 } 662 } 663 664 /* Order: 665 * { base class } or { __vptr, __monitor } 666 * interfaces 667 * fields 668 */ 669 670 uint offset; 671 if (cd) 672 { 673 if (ClassDeclaration cdb = cd.baseClass) 674 { 675 size_t index = 0; 676 for (ClassDeclaration c = cdb.baseClass; c; c = c.baseClass) 677 index += c.fields.dim; 678 membersToDt(cdb, dtb, elements, index, concreteType); 679 offset = cdb.structsize; 680 } 681 else if (InterfaceDeclaration id = cd.isInterfaceDeclaration()) 682 { 683 offset = (**ppb).offset; 684 if (id.vtblInterfaces.dim == 0) 685 { 686 BaseClass* b = **ppb; 687 //printf(" Interface %s, b = %p\n", id.toChars(), b); 688 ++(*ppb); 689 for (ClassDeclaration cd2 = concreteType; 1; cd2 = cd2.baseClass) 690 { 691 assert(cd2); 692 uint csymoffset = baseVtblOffset(cd2, b); 693 //printf(" cd2 %s csymoffset = x%x\n", cd2 ? cd2.toChars() : "null", csymoffset); 694 if (csymoffset != ~0) 695 { 696 dtb.xoff(toSymbol(cd2), csymoffset); 697 offset += target.ptrsize; 698 break; 699 } 700 } 701 } 702 } 703 else 704 { 705 dtb.xoff(toVtblSymbol(concreteType), 0); // __vptr 706 offset = target.ptrsize; 707 if (cd.hasMonitor()) 708 { 709 dtb.size(0); // __monitor 710 offset += target.ptrsize; 711 } 712 } 713 714 // Interface vptr initializations 715 toSymbol(cd); // define csym 716 717 BaseClass** pb; 718 if (!ppb) 719 { 720 pb = (*cd.vtblInterfaces)[].ptr; 721 ppb = &pb; 722 } 723 724 foreach (si; cd.interfaces[]) 725 { 726 BaseClass* b = **ppb; 727 if (offset < b.offset) 728 dtb.nzeros(b.offset - offset); 729 membersToDt(si.sym, dtb, elements, firstFieldIndex, concreteType, ppb); 730 //printf("b.offset = %d, b.sym.structsize = %d\n", (int)b.offset, (int)b.sym.structsize); 731 offset = b.offset + b.sym.structsize; 732 } 733 } 734 else 735 offset = 0; 736 737 assert(!elements || 738 firstFieldIndex <= elements.dim && 739 firstFieldIndex + ad.fields.dim <= elements.dim); 740 741 foreach (i, field; ad.fields) 742 { 743 if (elements && !(*elements)[firstFieldIndex + i]) 744 continue; 745 746 if (!elements || !(*elements)[firstFieldIndex + i]) 747 { 748 if (field._init && field._init.isVoidInitializer()) 749 continue; 750 } 751 752 VarDeclaration vd; 753 size_t k; 754 foreach (j; i .. ad.fields.length) 755 { 756 VarDeclaration v2 = ad.fields[j]; 757 if (v2.offset < offset) 758 continue; 759 760 if (elements && !(*elements)[firstFieldIndex + j]) 761 continue; 762 763 if (!elements || !(*elements)[firstFieldIndex + j]) 764 { 765 if (v2._init && v2._init.isVoidInitializer()) 766 continue; 767 } 768 769 // find the nearest field 770 if (!vd || v2.offset < vd.offset) 771 { 772 vd = v2; 773 k = j; 774 assert(vd == v2 || !vd.isOverlappedWith(v2)); 775 } 776 } 777 if (!vd) 778 continue; 779 780 assert(offset <= vd.offset); 781 if (offset < vd.offset) 782 dtb.nzeros(vd.offset - offset); 783 784 auto dtbx = DtBuilder(0); 785 if (elements) 786 { 787 Expression e = (*elements)[firstFieldIndex + k]; 788 if (auto tsa = vd.type.toBasetype().isTypeSArray()) 789 toDtElem(tsa, dtbx, e); 790 else 791 Expression_toDt(e, dtbx); // convert e to an initializer dt 792 } 793 else 794 { 795 if (Initializer init = vd._init) 796 { 797 //printf("\t\t%s has initializer %s\n", vd.toChars(), init.toChars()); 798 if (init.isVoidInitializer()) 799 continue; 800 801 assert(vd.semanticRun >= PASS.semantic2done); 802 803 auto ei = init.isExpInitializer(); 804 auto tsa = vd.type.toBasetype().isTypeSArray(); 805 if (ei && tsa) 806 toDtElem(tsa, dtbx, ei.exp); 807 else 808 Initializer_toDt(init, dtbx); 809 } 810 else if (offset <= vd.offset) 811 { 812 //printf("\t\tdefault initializer\n"); 813 Type_toDt(vd.type, dtbx); 814 } 815 if (dtbx.isZeroLength()) 816 continue; 817 } 818 819 dtb.cat(dtbx); 820 offset = cast(uint)(vd.offset + vd.type.size()); 821 } 822 823 if (offset < ad.structsize) 824 dtb.nzeros(ad.structsize - offset); 825 } 826 827 828 /* ================================================================= */ 829 830 extern (C++) void Type_toDt(Type t, ref DtBuilder dtb) 831 { 832 switch (t.ty) 833 { 834 case Tvector: 835 toDtElem(t.isTypeVector().basetype.isTypeSArray(), dtb, null); 836 break; 837 838 case Tsarray: 839 toDtElem(t.isTypeSArray(), dtb, null); 840 break; 841 842 case Tstruct: 843 StructDeclaration_toDt(t.isTypeStruct().sym, dtb); 844 break; 845 846 default: 847 Expression_toDt(t.defaultInit(Loc.initial), dtb); 848 break; 849 } 850 } 851 852 private void toDtElem(TypeSArray tsa, ref DtBuilder dtb, Expression e) 853 { 854 //printf("TypeSArray.toDtElem() tsa = %s\n", tsa.toChars()); 855 if (tsa.size(Loc.initial) == 0) 856 { 857 dtb.nzeros(0); 858 } 859 else 860 { 861 size_t len = cast(size_t)tsa.dim.toInteger(); 862 assert(len); 863 Type tnext = tsa.next; 864 Type tbn = tnext.toBasetype(); 865 Type ten = e ? e.type : null; 866 if (ten && (ten.ty == Tsarray || ten.ty == Tarray)) 867 ten = ten.nextOf(); 868 while (tbn.ty == Tsarray && (!e || !tbn.equivalent(ten))) 869 { 870 len *= tbn.isTypeSArray().dim.toInteger(); 871 tnext = tbn.nextOf(); 872 tbn = tnext.toBasetype(); 873 } 874 if (!e) // if not already supplied 875 e = tsa.defaultInit(Loc.initial); // use default initializer 876 877 if (!e.type.implicitConvTo(tnext)) // https://issues.dlang.org/show_bug.cgi?id=14996 878 { 879 // https://issues.dlang.org/show_bug.cgi?id=1914 880 // https://issues.dlang.org/show_bug.cgi?id=3198 881 if (auto se = e.isStringExp()) 882 len /= se.numberOfCodeUnits(); 883 else if (auto ae = e.isArrayLiteralExp()) 884 len /= ae.elements.dim; 885 } 886 887 auto dtb2 = DtBuilder(0); 888 Expression_toDt(e, dtb2); 889 dt_t* dt2 = dtb2.finish(); 890 assert(len <= uint.max); 891 dtb.repeat(dt2, cast(uint)len); 892 } 893 } 894 895 /*****************************************************/ 896 /* CTFE stuff */ 897 /*****************************************************/ 898 899 private void ClassReferenceExp_toDt(ClassReferenceExp e, ref DtBuilder dtb, int off) 900 { 901 //printf("ClassReferenceExp.toDt() %d\n", e.op); 902 Symbol* s = toSymbol(e); 903 dtb.xoff(s, off); 904 if (e.type.isMutable()) 905 write_instance_pointers(e.type, s, 0); 906 } 907 908 extern (C++) void ClassReferenceExp_toInstanceDt(ClassReferenceExp ce, ref DtBuilder dtb) 909 { 910 //printf("ClassReferenceExp.toInstanceDt() %d\n", ce.op); 911 ClassDeclaration cd = ce.originalClass(); 912 913 // Put in the rest 914 size_t firstFieldIndex = 0; 915 for (ClassDeclaration c = cd.baseClass; c; c = c.baseClass) 916 firstFieldIndex += c.fields.dim; 917 membersToDt(cd, dtb, ce.value.elements, firstFieldIndex, cd); 918 } 919 920 /**************************************************** 921 */ 922 private extern (C++) class TypeInfoDtVisitor : Visitor 923 { 924 DtBuilder* dtb; 925 926 /* 927 * Used in TypeInfo*.toDt to verify the runtime TypeInfo sizes 928 */ 929 static void verifyStructSize(ClassDeclaration typeclass, size_t expected) 930 { 931 if (typeclass.structsize != expected) 932 { 933 debug 934 { 935 printf("expected = x%x, %s.structsize = x%x\n", cast(uint)expected, 936 typeclass.toChars(), cast(uint)typeclass.structsize); 937 } 938 error(typeclass.loc, "`%s`: mismatch between compiler (%d bytes) and object.d or object.di (%d bytes) found. Check installation and import paths with -v compiler switch.", 939 typeclass.toChars(), cast(uint)expected, cast(uint)typeclass.structsize); 940 fatal(); 941 } 942 } 943 944 this(ref DtBuilder dtb) 945 { 946 this.dtb = &dtb; 947 } 948 949 alias visit = Visitor.visit; 950 951 override void visit(TypeInfoDeclaration d) 952 { 953 //printf("TypeInfoDeclaration.toDt() %s\n", toChars()); 954 verifyStructSize(Type.dtypeinfo, 2 * target.ptrsize); 955 956 dtb.xoff(toVtblSymbol(Type.dtypeinfo), 0); // vtbl for TypeInfo 957 if (Type.dtypeinfo.hasMonitor()) 958 dtb.size(0); // monitor 959 } 960 961 override void visit(TypeInfoConstDeclaration d) 962 { 963 //printf("TypeInfoConstDeclaration.toDt() %s\n", toChars()); 964 verifyStructSize(Type.typeinfoconst, 3 * target.ptrsize); 965 966 dtb.xoff(toVtblSymbol(Type.typeinfoconst), 0); // vtbl for TypeInfo_Const 967 if (Type.typeinfoconst.hasMonitor()) 968 dtb.size(0); // monitor 969 Type tm = d.tinfo.mutableOf(); 970 tm = tm.merge(); 971 genTypeInfo(d.loc, tm, null); 972 dtb.xoff(toSymbol(tm.vtinfo), 0); 973 } 974 975 override void visit(TypeInfoInvariantDeclaration d) 976 { 977 //printf("TypeInfoInvariantDeclaration.toDt() %s\n", toChars()); 978 verifyStructSize(Type.typeinfoinvariant, 3 * target.ptrsize); 979 980 dtb.xoff(toVtblSymbol(Type.typeinfoinvariant), 0); // vtbl for TypeInfo_Invariant 981 if (Type.typeinfoinvariant.hasMonitor()) 982 dtb.size(0); // monitor 983 Type tm = d.tinfo.mutableOf(); 984 tm = tm.merge(); 985 genTypeInfo(d.loc, tm, null); 986 dtb.xoff(toSymbol(tm.vtinfo), 0); 987 } 988 989 override void visit(TypeInfoSharedDeclaration d) 990 { 991 //printf("TypeInfoSharedDeclaration.toDt() %s\n", toChars()); 992 verifyStructSize(Type.typeinfoshared, 3 * target.ptrsize); 993 994 dtb.xoff(toVtblSymbol(Type.typeinfoshared), 0); // vtbl for TypeInfo_Shared 995 if (Type.typeinfoshared.hasMonitor()) 996 dtb.size(0); // monitor 997 Type tm = d.tinfo.unSharedOf(); 998 tm = tm.merge(); 999 genTypeInfo(d.loc, tm, null); 1000 dtb.xoff(toSymbol(tm.vtinfo), 0); 1001 } 1002 1003 override void visit(TypeInfoWildDeclaration d) 1004 { 1005 //printf("TypeInfoWildDeclaration.toDt() %s\n", toChars()); 1006 verifyStructSize(Type.typeinfowild, 3 * target.ptrsize); 1007 1008 dtb.xoff(toVtblSymbol(Type.typeinfowild), 0); // vtbl for TypeInfo_Wild 1009 if (Type.typeinfowild.hasMonitor()) 1010 dtb.size(0); // monitor 1011 Type tm = d.tinfo.mutableOf(); 1012 tm = tm.merge(); 1013 genTypeInfo(d.loc, tm, null); 1014 dtb.xoff(toSymbol(tm.vtinfo), 0); 1015 } 1016 1017 override void visit(TypeInfoEnumDeclaration d) 1018 { 1019 //printf("TypeInfoEnumDeclaration.toDt()\n"); 1020 verifyStructSize(Type.typeinfoenum, 7 * target.ptrsize); 1021 1022 dtb.xoff(toVtblSymbol(Type.typeinfoenum), 0); // vtbl for TypeInfo_Enum 1023 if (Type.typeinfoenum.hasMonitor()) 1024 dtb.size(0); // monitor 1025 1026 assert(d.tinfo.ty == Tenum); 1027 1028 TypeEnum tc = cast(TypeEnum)d.tinfo; 1029 EnumDeclaration sd = tc.sym; 1030 1031 /* Put out: 1032 * TypeInfo base; 1033 * string name; 1034 * void[] m_init; 1035 */ 1036 1037 // TypeInfo for enum members 1038 if (sd.memtype) 1039 { 1040 genTypeInfo(d.loc, sd.memtype, null); 1041 dtb.xoff(toSymbol(sd.memtype.vtinfo), 0); 1042 } 1043 else 1044 dtb.size(0); 1045 1046 // string name; 1047 const(char)* name = sd.toPrettyChars(); 1048 size_t namelen = strlen(name); 1049 dtb.size(namelen); 1050 dtb.xoff(d.csym, Type.typeinfoenum.structsize); 1051 1052 // void[] init; 1053 if (!sd.members || d.tinfo.isZeroInit(Loc.initial)) 1054 { 1055 // 0 initializer, or the same as the base type 1056 dtb.size(0); // init.length 1057 dtb.size(0); // init.ptr 1058 } 1059 else 1060 { 1061 dtb.size(sd.type.size()); // init.length 1062 dtb.xoff(toInitializer(sd), 0); // init.ptr 1063 } 1064 1065 // Put out name[] immediately following TypeInfo_Enum 1066 dtb.nbytes(cast(uint)(namelen + 1), name); 1067 } 1068 1069 override void visit(TypeInfoPointerDeclaration d) 1070 { 1071 //printf("TypeInfoPointerDeclaration.toDt()\n"); 1072 verifyStructSize(Type.typeinfopointer, 3 * target.ptrsize); 1073 1074 dtb.xoff(toVtblSymbol(Type.typeinfopointer), 0); // vtbl for TypeInfo_Pointer 1075 if (Type.typeinfopointer.hasMonitor()) 1076 dtb.size(0); // monitor 1077 1078 auto tc = d.tinfo.isTypePointer(); 1079 1080 genTypeInfo(d.loc, tc.next, null); 1081 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for type being pointed to 1082 } 1083 1084 override void visit(TypeInfoArrayDeclaration d) 1085 { 1086 //printf("TypeInfoArrayDeclaration.toDt()\n"); 1087 verifyStructSize(Type.typeinfoarray, 3 * target.ptrsize); 1088 1089 dtb.xoff(toVtblSymbol(Type.typeinfoarray), 0); // vtbl for TypeInfo_Array 1090 if (Type.typeinfoarray.hasMonitor()) 1091 dtb.size(0); // monitor 1092 1093 auto tc = d.tinfo.isTypeDArray(); 1094 1095 genTypeInfo(d.loc, tc.next, null); 1096 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for array of type 1097 } 1098 1099 override void visit(TypeInfoStaticArrayDeclaration d) 1100 { 1101 //printf("TypeInfoStaticArrayDeclaration.toDt()\n"); 1102 verifyStructSize(Type.typeinfostaticarray, 4 * target.ptrsize); 1103 1104 dtb.xoff(toVtblSymbol(Type.typeinfostaticarray), 0); // vtbl for TypeInfo_StaticArray 1105 if (Type.typeinfostaticarray.hasMonitor()) 1106 dtb.size(0); // monitor 1107 1108 auto tc = d.tinfo.isTypeSArray(); 1109 1110 genTypeInfo(d.loc, tc.next, null); 1111 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for array of type 1112 1113 dtb.size(tc.dim.toInteger()); // length 1114 } 1115 1116 override void visit(TypeInfoVectorDeclaration d) 1117 { 1118 //printf("TypeInfoVectorDeclaration.toDt()\n"); 1119 verifyStructSize(Type.typeinfovector, 3 * target.ptrsize); 1120 1121 dtb.xoff(toVtblSymbol(Type.typeinfovector), 0); // vtbl for TypeInfo_Vector 1122 if (Type.typeinfovector.hasMonitor()) 1123 dtb.size(0); // monitor 1124 1125 auto tc = d.tinfo.isTypeVector(); 1126 1127 genTypeInfo(d.loc, tc.basetype, null); 1128 dtb.xoff(toSymbol(tc.basetype.vtinfo), 0); // TypeInfo for equivalent static array 1129 } 1130 1131 override void visit(TypeInfoAssociativeArrayDeclaration d) 1132 { 1133 //printf("TypeInfoAssociativeArrayDeclaration.toDt()\n"); 1134 verifyStructSize(Type.typeinfoassociativearray, 4 * target.ptrsize); 1135 1136 dtb.xoff(toVtblSymbol(Type.typeinfoassociativearray), 0); // vtbl for TypeInfo_AssociativeArray 1137 if (Type.typeinfoassociativearray.hasMonitor()) 1138 dtb.size(0); // monitor 1139 1140 auto tc = d.tinfo.isTypeAArray(); 1141 1142 genTypeInfo(d.loc, tc.next, null); 1143 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for array of type 1144 1145 genTypeInfo(d.loc, tc.index, null); 1146 dtb.xoff(toSymbol(tc.index.vtinfo), 0); // TypeInfo for array of type 1147 } 1148 1149 override void visit(TypeInfoFunctionDeclaration d) 1150 { 1151 //printf("TypeInfoFunctionDeclaration.toDt()\n"); 1152 verifyStructSize(Type.typeinfofunction, 5 * target.ptrsize); 1153 1154 dtb.xoff(toVtblSymbol(Type.typeinfofunction), 0); // vtbl for TypeInfo_Function 1155 if (Type.typeinfofunction.hasMonitor()) 1156 dtb.size(0); // monitor 1157 1158 auto tc = d.tinfo.isTypeFunction(); 1159 1160 genTypeInfo(d.loc, tc.next, null); 1161 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for function return value 1162 1163 const name = d.tinfo.deco; 1164 assert(name); 1165 const namelen = strlen(name); 1166 dtb.size(namelen); 1167 dtb.xoff(d.csym, Type.typeinfofunction.structsize); 1168 1169 // Put out name[] immediately following TypeInfo_Function 1170 dtb.nbytes(cast(uint)(namelen + 1), name); 1171 } 1172 1173 override void visit(TypeInfoDelegateDeclaration d) 1174 { 1175 //printf("TypeInfoDelegateDeclaration.toDt()\n"); 1176 verifyStructSize(Type.typeinfodelegate, 5 * target.ptrsize); 1177 1178 dtb.xoff(toVtblSymbol(Type.typeinfodelegate), 0); // vtbl for TypeInfo_Delegate 1179 if (Type.typeinfodelegate.hasMonitor()) 1180 dtb.size(0); // monitor 1181 1182 auto tc = d.tinfo.isTypeDelegate(); 1183 1184 genTypeInfo(d.loc, tc.next.nextOf(), null); 1185 dtb.xoff(toSymbol(tc.next.nextOf().vtinfo), 0); // TypeInfo for delegate return value 1186 1187 const name = d.tinfo.deco; 1188 assert(name); 1189 const namelen = strlen(name); 1190 dtb.size(namelen); 1191 dtb.xoff(d.csym, Type.typeinfodelegate.structsize); 1192 1193 // Put out name[] immediately following TypeInfo_Delegate 1194 dtb.nbytes(cast(uint)(namelen + 1), name); 1195 } 1196 1197 override void visit(TypeInfoStructDeclaration d) 1198 { 1199 //printf("TypeInfoStructDeclaration.toDt() '%s'\n", d.toChars()); 1200 if (global.params.is64bit) 1201 verifyStructSize(Type.typeinfostruct, 17 * target.ptrsize); 1202 else 1203 verifyStructSize(Type.typeinfostruct, 15 * target.ptrsize); 1204 1205 dtb.xoff(toVtblSymbol(Type.typeinfostruct), 0); // vtbl for TypeInfo_Struct 1206 if (Type.typeinfostruct.hasMonitor()) 1207 dtb.size(0); // monitor 1208 1209 auto tc = d.tinfo.isTypeStruct(); 1210 StructDeclaration sd = tc.sym; 1211 1212 if (!sd.members) 1213 return; 1214 1215 if (TemplateInstance ti = sd.isInstantiated()) 1216 { 1217 if (!ti.needsCodegen()) 1218 { 1219 assert(ti.minst || sd.requestTypeInfo); 1220 1221 /* ti.toObjFile() won't get called. So, store these 1222 * member functions into object file in here. 1223 */ 1224 if (sd.xeq && sd.xeq != StructDeclaration.xerreq) 1225 toObjFile(sd.xeq, global.params.multiobj); 1226 if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp) 1227 toObjFile(sd.xcmp, global.params.multiobj); 1228 if (FuncDeclaration ftostr = search_toString(sd)) 1229 toObjFile(ftostr, global.params.multiobj); 1230 if (sd.xhash) 1231 toObjFile(sd.xhash, global.params.multiobj); 1232 if (sd.postblit) 1233 toObjFile(sd.postblit, global.params.multiobj); 1234 if (sd.dtor) 1235 toObjFile(sd.dtor, global.params.multiobj); 1236 } 1237 } 1238 1239 /* Put out: 1240 * char[] name; 1241 * void[] init; 1242 * hash_t function(in void*) xtoHash; 1243 * bool function(in void*, in void*) xopEquals; 1244 * int function(in void*, in void*) xopCmp; 1245 * string function(const(void)*) xtoString; 1246 * StructFlags m_flags; 1247 * //xgetMembers; 1248 * xdtor; 1249 * xpostblit; 1250 * uint m_align; 1251 * version (X86_64) 1252 * TypeInfo m_arg1; 1253 * TypeInfo m_arg2; 1254 * xgetRTInfo 1255 */ 1256 1257 const name = sd.toPrettyChars(); 1258 const namelen = strlen(name); 1259 dtb.size(namelen); 1260 dtb.xoff(d.csym, Type.typeinfostruct.structsize); 1261 1262 // void[] init; 1263 dtb.size(sd.structsize); // init.length 1264 if (sd.zeroInit) 1265 dtb.size(0); // null for 0 initialization 1266 else 1267 dtb.xoff(toInitializer(sd), 0); // init.ptr 1268 1269 if (FuncDeclaration fd = sd.xhash) 1270 { 1271 dtb.xoff(toSymbol(fd), 0); 1272 TypeFunction tf = cast(TypeFunction)fd.type; 1273 assert(tf.ty == Tfunction); 1274 /* I'm a little unsure this is the right way to do it. Perhaps a better 1275 * way would to automatically add these attributes to any struct member 1276 * function with the name "toHash". 1277 * So I'm leaving this here as an experiment for the moment. 1278 */ 1279 if (!tf.isnothrow || tf.trust == TRUST.system /*|| tf.purity == PURE.impure*/) 1280 warning(fd.loc, "toHash() must be declared as extern (D) size_t toHash() const nothrow @safe, not %s", tf.toChars()); 1281 } 1282 else 1283 dtb.size(0); 1284 1285 if (sd.xeq) 1286 dtb.xoff(toSymbol(sd.xeq), 0); 1287 else 1288 dtb.size(0); 1289 1290 if (sd.xcmp) 1291 dtb.xoff(toSymbol(sd.xcmp), 0); 1292 else 1293 dtb.size(0); 1294 1295 if (FuncDeclaration fd = search_toString(sd)) 1296 { 1297 dtb.xoff(toSymbol(fd), 0); 1298 } 1299 else 1300 dtb.size(0); 1301 1302 // StructFlags m_flags; 1303 StructFlags m_flags = StructFlags.none; 1304 if (tc.hasPointers()) m_flags |= StructFlags.hasPointers; 1305 dtb.size(m_flags); 1306 1307 version (none) 1308 { 1309 // xgetMembers 1310 if (auto sgetmembers = sd.findGetMembers()) 1311 dtb.xoff(toSymbol(sgetmembers), 0); 1312 else 1313 dtb.size(0); // xgetMembers 1314 } 1315 1316 // xdtor 1317 if (auto sdtor = sd.tidtor) 1318 dtb.xoff(toSymbol(sdtor), 0); 1319 else 1320 dtb.size(0); // xdtor 1321 1322 // xpostblit 1323 FuncDeclaration spostblit = sd.postblit; 1324 if (spostblit && !(spostblit.storage_class & STC.disable)) 1325 dtb.xoff(toSymbol(spostblit), 0); 1326 else 1327 dtb.size(0); // xpostblit 1328 1329 // uint m_align; 1330 dtb.size(tc.alignsize()); 1331 1332 if (global.params.is64bit) 1333 { 1334 foreach (i; 0 .. 2) 1335 { 1336 // m_argi 1337 if (auto t = sd.argType(i)) 1338 { 1339 genTypeInfo(d.loc, t, null); 1340 dtb.xoff(toSymbol(t.vtinfo), 0); 1341 } 1342 else 1343 dtb.size(0); 1344 } 1345 } 1346 1347 // xgetRTInfo 1348 if (sd.getRTInfo) 1349 { 1350 Expression_toDt(sd.getRTInfo, *dtb); 1351 } 1352 else if (m_flags & StructFlags.hasPointers) 1353 dtb.size(1); 1354 else 1355 dtb.size(0); 1356 1357 // Put out name[] immediately following TypeInfo_Struct 1358 dtb.nbytes(cast(uint)(namelen + 1), name); 1359 } 1360 1361 override void visit(TypeInfoClassDeclaration d) 1362 { 1363 //printf("TypeInfoClassDeclaration.toDt() %s\n", tinfo.toChars()); 1364 assert(0); 1365 } 1366 1367 override void visit(TypeInfoInterfaceDeclaration d) 1368 { 1369 //printf("TypeInfoInterfaceDeclaration.toDt() %s\n", tinfo.toChars()); 1370 verifyStructSize(Type.typeinfointerface, 3 * target.ptrsize); 1371 1372 dtb.xoff(toVtblSymbol(Type.typeinfointerface), 0); // vtbl for TypeInfoInterface 1373 if (Type.typeinfointerface.hasMonitor()) 1374 dtb.size(0); // monitor 1375 1376 auto tc = d.tinfo.isTypeClass(); 1377 1378 if (!tc.sym.vclassinfo) 1379 tc.sym.vclassinfo = TypeInfoClassDeclaration.create(tc); 1380 auto s = toSymbol(tc.sym.vclassinfo); 1381 dtb.xoff(s, 0); // ClassInfo for tinfo 1382 } 1383 1384 override void visit(TypeInfoTupleDeclaration d) 1385 { 1386 //printf("TypeInfoTupleDeclaration.toDt() %s\n", tinfo.toChars()); 1387 verifyStructSize(Type.typeinfotypelist, 4 * target.ptrsize); 1388 1389 dtb.xoff(toVtblSymbol(Type.typeinfotypelist), 0); // vtbl for TypeInfoInterface 1390 if (Type.typeinfotypelist.hasMonitor()) 1391 dtb.size(0); // monitor 1392 1393 auto tu = d.tinfo.isTypeTuple(); 1394 1395 const dim = tu.arguments.dim; 1396 dtb.size(dim); // elements.length 1397 1398 auto dtbargs = DtBuilder(0); 1399 foreach (arg; *tu.arguments) 1400 { 1401 genTypeInfo(d.loc, arg.type, null); 1402 Symbol* s = toSymbol(arg.type.vtinfo); 1403 dtbargs.xoff(s, 0); 1404 } 1405 1406 dtb.dtoff(dtbargs.finish(), 0); // elements.ptr 1407 } 1408 } 1409 1410 extern (C++) void TypeInfo_toDt(ref DtBuilder dtb, TypeInfoDeclaration d) 1411 { 1412 scope v = new TypeInfoDtVisitor(dtb); 1413 d.accept(v); 1414 }