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-2020 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, %d, for array[%d]", ai.dim, 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 dtb.abytes(0, n * e.sz, p, cast(uint)e.sz); 394 break; 395 396 case Tsarray: 397 { 398 auto tsa = t.isTypeSArray(); 399 400 dtb.nbytes(n * e.sz, p); 401 if (tsa.dim) 402 { 403 dinteger_t dim = tsa.dim.toInteger(); 404 if (n < dim) 405 { 406 // Pad remainder with 0 407 dtb.nzeros(cast(uint)((dim - n) * tsa.next.size())); 408 } 409 } 410 break; 411 } 412 413 default: 414 printf("StringExp.toDt(type = %s)\n", e.type.toChars()); 415 assert(0); 416 } 417 mem.xfree(q); 418 } 419 420 void visitArrayLiteral(ArrayLiteralExp e) 421 { 422 //printf("ArrayLiteralExp.toDt() '%s', type = %s\n", e.toChars(), e.type.toChars()); 423 424 auto dtbarray = DtBuilder(0); 425 foreach (i; 0 .. e.elements.dim) 426 { 427 Expression_toDt(e[i], dtbarray); 428 } 429 430 Type t = e.type.toBasetype(); 431 switch (t.ty) 432 { 433 case Tsarray: 434 dtb.cat(dtbarray); 435 break; 436 437 case Tarray: 438 dtb.size(e.elements.dim); 439 goto case Tpointer; 440 441 case Tpointer: 442 { 443 if (auto d = dtbarray.finish()) 444 dtb.dtoff(d, 0); 445 else 446 dtb.size(0); 447 448 break; 449 } 450 451 default: 452 assert(0); 453 } 454 } 455 456 void visitStructLiteral(StructLiteralExp sle) 457 { 458 //printf("StructLiteralExp.toDt() %s, ctfe = %d\n", sle.toChars(), sle.ownedByCtfe); 459 assert(sle.sd.nonHiddenFields() <= sle.elements.dim); 460 membersToDt(sle.sd, dtb, sle.elements, 0, null); 461 } 462 463 void visitSymOff(SymOffExp e) 464 { 465 //printf("SymOffExp.toDt('%s')\n", e.var.toChars()); 466 assert(e.var); 467 if (!(e.var.isDataseg() || e.var.isCodeseg()) || 468 e.var.needThis() || 469 e.var.isThreadlocal()) 470 { 471 return nonConstExpError(e); 472 } 473 dtb.xoff(toSymbol(e.var), cast(uint)e.offset); 474 } 475 476 void visitVar(VarExp e) 477 { 478 //printf("VarExp.toDt() %d\n", e.op); 479 480 if (auto v = e.var.isVarDeclaration()) 481 { 482 if ((v.isConst() || v.isImmutable()) && 483 e.type.toBasetype().ty != Tsarray && v._init) 484 { 485 e.error("recursive reference `%s`", e.toChars()); 486 return; 487 } 488 v.inuse++; 489 Initializer_toDt(v._init, dtb); 490 v.inuse--; 491 return; 492 } 493 494 if (auto sd = e.var.isSymbolDeclaration()) 495 if (sd.dsym) 496 { 497 StructDeclaration_toDt(sd.dsym, dtb); 498 return; 499 } 500 501 return nonConstExpError(e); 502 } 503 504 void visitFunc(FuncExp e) 505 { 506 //printf("FuncExp.toDt() %d\n", e.op); 507 if (e.fd.tok == TOK.reserved && e.type.ty == Tpointer) 508 { 509 // change to non-nested 510 e.fd.tok = TOK.function_; 511 e.fd.vthis = null; 512 } 513 Symbol *s = toSymbol(e.fd); 514 toObjFile(e.fd, false); 515 if (e.fd.tok == TOK.delegate_) 516 dtb.size(0); 517 dtb.xoff(s, 0); 518 } 519 520 void visitVector(VectorExp e) 521 { 522 //printf("VectorExp.toDt() %s\n", e.toChars()); 523 foreach (i; 0 .. e.dim) 524 { 525 Expression elem; 526 if (auto ale = e.e1.isArrayLiteralExp()) 527 elem = ale[i]; 528 else 529 elem = e.e1; 530 Expression_toDt(elem, dtb); 531 } 532 } 533 534 void visitClassReference(ClassReferenceExp e) 535 { 536 InterfaceDeclaration to = (cast(TypeClass)e.type).sym.isInterfaceDeclaration(); 537 538 if (to) //Static typeof this literal is an interface. We must add offset to symbol 539 { 540 ClassDeclaration from = e.originalClass(); 541 int off = 0; 542 const isbase = to.isBaseOf(from, &off); 543 assert(isbase); 544 ClassReferenceExp_toDt(e, dtb, off); 545 } 546 else 547 ClassReferenceExp_toDt(e, dtb, 0); 548 } 549 550 void visitTypeid(TypeidExp e) 551 { 552 if (Type t = isType(e.obj)) 553 { 554 genTypeInfo(e.loc, t, null); 555 Symbol *s = toSymbol(t.vtinfo); 556 dtb.xoff(s, 0); 557 return; 558 } 559 assert(0); 560 } 561 562 switch (e.op) 563 { 564 default: return nonConstExpError(e); 565 case TOK.cast_: return visitCast (e.isCastExp()); 566 case TOK.address: return visitAddr (e.isAddrExp()); 567 case TOK.int64: return visitInteger (e.isIntegerExp()); 568 case TOK.float64: return visitReal (e.isRealExp()); 569 case TOK.complex80: return visitComplex (e.isComplexExp()); 570 case TOK.null_: return visitNull (e.isNullExp()); 571 case TOK.string_: return visitString (e.isStringExp()); 572 case TOK.arrayLiteral: return visitArrayLiteral (e.isArrayLiteralExp()); 573 case TOK.structLiteral: return visitStructLiteral (e.isStructLiteralExp()); 574 case TOK.symbolOffset: return visitSymOff (e.isSymOffExp()); 575 case TOK.variable: return visitVar (e.isVarExp()); 576 case TOK.function_: return visitFunc (e.isFuncExp()); 577 case TOK.vector: return visitVector (e.isVectorExp()); 578 case TOK.classReference: return visitClassReference(e.isClassReferenceExp()); 579 case TOK.typeid_: return visitTypeid (e.isTypeidExp()); 580 } 581 } 582 583 /* ================================================================= */ 584 585 // Generate the data for the static initializer. 586 587 extern (C++) void ClassDeclaration_toDt(ClassDeclaration cd, ref DtBuilder dtb) 588 { 589 //printf("ClassDeclaration.toDt(this = '%s')\n", cd.toChars()); 590 591 membersToDt(cd, dtb, null, 0, cd); 592 593 //printf("-ClassDeclaration.toDt(this = '%s')\n", cd.toChars()); 594 } 595 596 extern (C++) void StructDeclaration_toDt(StructDeclaration sd, ref DtBuilder dtb) 597 { 598 //printf("+StructDeclaration.toDt(), this='%s'\n", sd.toChars()); 599 membersToDt(sd, dtb, null, 0, null); 600 601 //printf("-StructDeclaration.toDt(), this='%s'\n", sd.toChars()); 602 } 603 604 /****************************** 605 * Generate data for instance of __cpp_type_info_ptr that refers 606 * to the C++ RTTI symbol for cd. 607 * Params: 608 * cd = C++ class 609 * dtb = data table builder 610 */ 611 extern (C++) void cpp_type_info_ptr_toDt(ClassDeclaration cd, ref DtBuilder dtb) 612 { 613 //printf("cpp_type_info_ptr_toDt(this = '%s')\n", cd.toChars()); 614 assert(cd.isCPPclass()); 615 616 // Put in first two members, the vtbl[] and the monitor 617 dtb.xoff(toVtblSymbol(ClassDeclaration.cpp_type_info_ptr), 0); 618 if (ClassDeclaration.cpp_type_info_ptr.hasMonitor()) 619 dtb.size(0); // monitor 620 621 // Create symbol for C++ type info 622 Symbol *s = toSymbolCppTypeInfo(cd); 623 624 // Put in address of cd's C++ type info 625 dtb.xoff(s, 0); 626 627 //printf("-cpp_type_info_ptr_toDt(this = '%s')\n", cd.toChars()); 628 } 629 630 /**************************************************** 631 * Put out initializers of ad.fields[]. 632 * Although this is consistent with the elements[] version, we 633 * have to use this optimized version to reduce memory footprint. 634 * Params: 635 * ad = aggregate with members 636 * pdt = tail of initializer list to start appending initialized data to 637 * elements = values to use as initializers, null means use default initializers 638 * firstFieldIndex = starting place is elements[firstFieldIndex] 639 * concreteType = structs: null, classes: most derived class 640 * ppb = pointer that moves through BaseClass[] from most derived class 641 * Returns: 642 * updated tail of dt_t list 643 */ 644 645 private void membersToDt(AggregateDeclaration ad, ref DtBuilder dtb, 646 Expressions* elements, size_t firstFieldIndex, 647 ClassDeclaration concreteType, 648 BaseClass*** ppb = null) 649 { 650 //printf("membersToDt(ad = '%s', concrete = '%s', ppb = %p)\n", ad.toChars(), concreteType ? concreteType.toChars() : "null", ppb); 651 ClassDeclaration cd = ad.isClassDeclaration(); 652 version (none) 653 { 654 printf(" interfaces.length = %d\n", cast(int)cd.interfaces.length); 655 foreach (i, b; cd.vtblInterfaces[]) 656 { 657 printf(" vbtblInterfaces[%d] b = %p, b.sym = %s\n", cast(int)i, b, b.sym.toChars()); 658 } 659 } 660 661 /* Order: 662 * { base class } or { __vptr, __monitor } 663 * interfaces 664 * fields 665 */ 666 667 uint offset; 668 if (cd) 669 { 670 if (ClassDeclaration cdb = cd.baseClass) 671 { 672 size_t index = 0; 673 for (ClassDeclaration c = cdb.baseClass; c; c = c.baseClass) 674 index += c.fields.dim; 675 membersToDt(cdb, dtb, elements, index, concreteType); 676 offset = cdb.structsize; 677 } 678 else if (InterfaceDeclaration id = cd.isInterfaceDeclaration()) 679 { 680 offset = (**ppb).offset; 681 if (id.vtblInterfaces.dim == 0) 682 { 683 BaseClass* b = **ppb; 684 //printf(" Interface %s, b = %p\n", id.toChars(), b); 685 ++(*ppb); 686 for (ClassDeclaration cd2 = concreteType; 1; cd2 = cd2.baseClass) 687 { 688 assert(cd2); 689 uint csymoffset = baseVtblOffset(cd2, b); 690 //printf(" cd2 %s csymoffset = x%x\n", cd2 ? cd2.toChars() : "null", csymoffset); 691 if (csymoffset != ~0) 692 { 693 dtb.xoff(toSymbol(cd2), csymoffset); 694 offset += target.ptrsize; 695 break; 696 } 697 } 698 } 699 } 700 else 701 { 702 dtb.xoff(toVtblSymbol(concreteType), 0); // __vptr 703 offset = target.ptrsize; 704 if (cd.hasMonitor()) 705 { 706 dtb.size(0); // __monitor 707 offset += target.ptrsize; 708 } 709 } 710 711 // Interface vptr initializations 712 toSymbol(cd); // define csym 713 714 BaseClass** pb; 715 if (!ppb) 716 { 717 pb = (*cd.vtblInterfaces)[].ptr; 718 ppb = &pb; 719 } 720 721 foreach (si; cd.interfaces[]) 722 { 723 BaseClass* b = **ppb; 724 if (offset < b.offset) 725 dtb.nzeros(b.offset - offset); 726 membersToDt(si.sym, dtb, elements, firstFieldIndex, concreteType, ppb); 727 //printf("b.offset = %d, b.sym.structsize = %d\n", (int)b.offset, (int)b.sym.structsize); 728 offset = b.offset + b.sym.structsize; 729 } 730 } 731 else 732 offset = 0; 733 734 assert(!elements || 735 firstFieldIndex <= elements.dim && 736 firstFieldIndex + ad.fields.dim <= elements.dim); 737 738 foreach (i, field; ad.fields) 739 { 740 if (elements && !(*elements)[firstFieldIndex + i]) 741 continue; 742 743 if (!elements || !(*elements)[firstFieldIndex + i]) 744 { 745 if (field._init && field._init.isVoidInitializer()) 746 continue; 747 } 748 749 VarDeclaration vd; 750 size_t k; 751 foreach (j; i .. ad.fields.length) 752 { 753 VarDeclaration v2 = ad.fields[j]; 754 if (v2.offset < offset) 755 continue; 756 757 if (elements && !(*elements)[firstFieldIndex + j]) 758 continue; 759 760 if (!elements || !(*elements)[firstFieldIndex + j]) 761 { 762 if (v2._init && v2._init.isVoidInitializer()) 763 continue; 764 } 765 766 // find the nearest field 767 if (!vd || v2.offset < vd.offset) 768 { 769 vd = v2; 770 k = j; 771 assert(vd == v2 || !vd.isOverlappedWith(v2)); 772 } 773 } 774 if (!vd) 775 continue; 776 777 assert(offset <= vd.offset); 778 if (offset < vd.offset) 779 dtb.nzeros(vd.offset - offset); 780 781 auto dtbx = DtBuilder(0); 782 if (elements) 783 { 784 Expression e = (*elements)[firstFieldIndex + k]; 785 if (auto tsa = vd.type.toBasetype().isTypeSArray()) 786 toDtElem(tsa, dtbx, e); 787 else 788 Expression_toDt(e, dtbx); // convert e to an initializer dt 789 } 790 else 791 { 792 if (Initializer init = vd._init) 793 { 794 //printf("\t\t%s has initializer %s\n", vd.toChars(), init.toChars()); 795 if (init.isVoidInitializer()) 796 continue; 797 798 assert(vd.semanticRun >= PASS.semantic2done); 799 800 auto ei = init.isExpInitializer(); 801 auto tsa = vd.type.toBasetype().isTypeSArray(); 802 if (ei && tsa) 803 toDtElem(tsa, dtbx, ei.exp); 804 else 805 Initializer_toDt(init, dtbx); 806 } 807 else if (offset <= vd.offset) 808 { 809 //printf("\t\tdefault initializer\n"); 810 Type_toDt(vd.type, dtbx); 811 } 812 if (dtbx.isZeroLength()) 813 continue; 814 } 815 816 dtb.cat(dtbx); 817 offset = cast(uint)(vd.offset + vd.type.size()); 818 } 819 820 if (offset < ad.structsize) 821 dtb.nzeros(ad.structsize - offset); 822 } 823 824 825 /* ================================================================= */ 826 827 extern (C++) void Type_toDt(Type t, ref DtBuilder dtb) 828 { 829 switch (t.ty) 830 { 831 case Tvector: 832 toDtElem(t.isTypeVector().basetype.isTypeSArray(), dtb, null); 833 break; 834 835 case Tsarray: 836 toDtElem(t.isTypeSArray(), dtb, null); 837 break; 838 839 case Tstruct: 840 StructDeclaration_toDt(t.isTypeStruct().sym, dtb); 841 break; 842 843 default: 844 Expression_toDt(t.defaultInit(Loc.initial), dtb); 845 break; 846 } 847 } 848 849 private void toDtElem(TypeSArray tsa, ref DtBuilder dtb, Expression e) 850 { 851 //printf("TypeSArray.toDtElem() tsa = %s\n", tsa.toChars()); 852 if (tsa.size(Loc.initial) == 0) 853 { 854 dtb.nzeros(0); 855 } 856 else 857 { 858 size_t len = cast(size_t)tsa.dim.toInteger(); 859 assert(len); 860 Type tnext = tsa.next; 861 Type tbn = tnext.toBasetype(); 862 Type ten = e ? e.type : null; 863 if (ten && (ten.ty == Tsarray || ten.ty == Tarray)) 864 ten = ten.nextOf(); 865 while (tbn.ty == Tsarray && (!e || !tbn.equivalent(ten))) 866 { 867 len *= tbn.isTypeSArray().dim.toInteger(); 868 tnext = tbn.nextOf(); 869 tbn = tnext.toBasetype(); 870 } 871 if (!e) // if not already supplied 872 e = tsa.defaultInit(Loc.initial); // use default initializer 873 874 if (!e.type.implicitConvTo(tnext)) // https://issues.dlang.org/show_bug.cgi?id=14996 875 { 876 // https://issues.dlang.org/show_bug.cgi?id=1914 877 // https://issues.dlang.org/show_bug.cgi?id=3198 878 if (auto se = e.isStringExp()) 879 len /= se.numberOfCodeUnits(); 880 else if (auto ae = e.isArrayLiteralExp()) 881 len /= ae.elements.dim; 882 } 883 884 auto dtb2 = DtBuilder(0); 885 Expression_toDt(e, dtb2); 886 dt_t* dt2 = dtb2.finish(); 887 assert(len <= uint.max); 888 dtb.repeat(dt2, cast(uint)len); 889 } 890 } 891 892 /*****************************************************/ 893 /* CTFE stuff */ 894 /*****************************************************/ 895 896 private void ClassReferenceExp_toDt(ClassReferenceExp e, ref DtBuilder dtb, int off) 897 { 898 //printf("ClassReferenceExp.toDt() %d\n", e.op); 899 Symbol* s = toSymbol(e); 900 dtb.xoff(s, off); 901 if (e.type.isMutable()) 902 write_instance_pointers(e.type, s, 0); 903 } 904 905 extern (C++) void ClassReferenceExp_toInstanceDt(ClassReferenceExp ce, ref DtBuilder dtb) 906 { 907 //printf("ClassReferenceExp.toInstanceDt() %d\n", ce.op); 908 ClassDeclaration cd = ce.originalClass(); 909 910 // Put in the rest 911 size_t firstFieldIndex = 0; 912 for (ClassDeclaration c = cd.baseClass; c; c = c.baseClass) 913 firstFieldIndex += c.fields.dim; 914 membersToDt(cd, dtb, ce.value.elements, firstFieldIndex, cd); 915 } 916 917 /**************************************************** 918 */ 919 private extern (C++) class TypeInfoDtVisitor : Visitor 920 { 921 DtBuilder* dtb; 922 923 /* 924 * Used in TypeInfo*.toDt to verify the runtime TypeInfo sizes 925 */ 926 static void verifyStructSize(ClassDeclaration typeclass, size_t expected) 927 { 928 if (typeclass.structsize != expected) 929 { 930 debug 931 { 932 printf("expected = x%x, %s.structsize = x%x\n", cast(uint)expected, 933 typeclass.toChars(), cast(uint)typeclass.structsize); 934 } 935 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.", 936 typeclass.toChars(), cast(uint)expected, cast(uint)typeclass.structsize); 937 fatal(); 938 } 939 } 940 941 this(ref DtBuilder dtb) 942 { 943 this.dtb = &dtb; 944 } 945 946 alias visit = Visitor.visit; 947 948 override void visit(TypeInfoDeclaration d) 949 { 950 //printf("TypeInfoDeclaration.toDt() %s\n", toChars()); 951 verifyStructSize(Type.dtypeinfo, 2 * target.ptrsize); 952 953 dtb.xoff(toVtblSymbol(Type.dtypeinfo), 0); // vtbl for TypeInfo 954 if (Type.dtypeinfo.hasMonitor()) 955 dtb.size(0); // monitor 956 } 957 958 override void visit(TypeInfoConstDeclaration d) 959 { 960 //printf("TypeInfoConstDeclaration.toDt() %s\n", toChars()); 961 verifyStructSize(Type.typeinfoconst, 3 * target.ptrsize); 962 963 dtb.xoff(toVtblSymbol(Type.typeinfoconst), 0); // vtbl for TypeInfo_Const 964 if (Type.typeinfoconst.hasMonitor()) 965 dtb.size(0); // monitor 966 Type tm = d.tinfo.mutableOf(); 967 tm = tm.merge(); 968 genTypeInfo(d.loc, tm, null); 969 dtb.xoff(toSymbol(tm.vtinfo), 0); 970 } 971 972 override void visit(TypeInfoInvariantDeclaration d) 973 { 974 //printf("TypeInfoInvariantDeclaration.toDt() %s\n", toChars()); 975 verifyStructSize(Type.typeinfoinvariant, 3 * target.ptrsize); 976 977 dtb.xoff(toVtblSymbol(Type.typeinfoinvariant), 0); // vtbl for TypeInfo_Invariant 978 if (Type.typeinfoinvariant.hasMonitor()) 979 dtb.size(0); // monitor 980 Type tm = d.tinfo.mutableOf(); 981 tm = tm.merge(); 982 genTypeInfo(d.loc, tm, null); 983 dtb.xoff(toSymbol(tm.vtinfo), 0); 984 } 985 986 override void visit(TypeInfoSharedDeclaration d) 987 { 988 //printf("TypeInfoSharedDeclaration.toDt() %s\n", toChars()); 989 verifyStructSize(Type.typeinfoshared, 3 * target.ptrsize); 990 991 dtb.xoff(toVtblSymbol(Type.typeinfoshared), 0); // vtbl for TypeInfo_Shared 992 if (Type.typeinfoshared.hasMonitor()) 993 dtb.size(0); // monitor 994 Type tm = d.tinfo.unSharedOf(); 995 tm = tm.merge(); 996 genTypeInfo(d.loc, tm, null); 997 dtb.xoff(toSymbol(tm.vtinfo), 0); 998 } 999 1000 override void visit(TypeInfoWildDeclaration d) 1001 { 1002 //printf("TypeInfoWildDeclaration.toDt() %s\n", toChars()); 1003 verifyStructSize(Type.typeinfowild, 3 * target.ptrsize); 1004 1005 dtb.xoff(toVtblSymbol(Type.typeinfowild), 0); // vtbl for TypeInfo_Wild 1006 if (Type.typeinfowild.hasMonitor()) 1007 dtb.size(0); // monitor 1008 Type tm = d.tinfo.mutableOf(); 1009 tm = tm.merge(); 1010 genTypeInfo(d.loc, tm, null); 1011 dtb.xoff(toSymbol(tm.vtinfo), 0); 1012 } 1013 1014 override void visit(TypeInfoEnumDeclaration d) 1015 { 1016 //printf("TypeInfoEnumDeclaration.toDt()\n"); 1017 verifyStructSize(Type.typeinfoenum, 7 * target.ptrsize); 1018 1019 dtb.xoff(toVtblSymbol(Type.typeinfoenum), 0); // vtbl for TypeInfo_Enum 1020 if (Type.typeinfoenum.hasMonitor()) 1021 dtb.size(0); // monitor 1022 1023 assert(d.tinfo.ty == Tenum); 1024 1025 TypeEnum tc = cast(TypeEnum)d.tinfo; 1026 EnumDeclaration sd = tc.sym; 1027 1028 /* Put out: 1029 * TypeInfo base; 1030 * string name; 1031 * void[] m_init; 1032 */ 1033 1034 // TypeInfo for enum members 1035 if (sd.memtype) 1036 { 1037 genTypeInfo(d.loc, sd.memtype, null); 1038 dtb.xoff(toSymbol(sd.memtype.vtinfo), 0); 1039 } 1040 else 1041 dtb.size(0); 1042 1043 // string name; 1044 const(char)* name = sd.toPrettyChars(); 1045 size_t namelen = strlen(name); 1046 dtb.size(namelen); 1047 dtb.xoff(d.csym, Type.typeinfoenum.structsize); 1048 1049 // void[] init; 1050 if (!sd.members || d.tinfo.isZeroInit(Loc.initial)) 1051 { 1052 // 0 initializer, or the same as the base type 1053 dtb.size(0); // init.length 1054 dtb.size(0); // init.ptr 1055 } 1056 else 1057 { 1058 dtb.size(sd.type.size()); // init.length 1059 dtb.xoff(toInitializer(sd), 0); // init.ptr 1060 } 1061 1062 // Put out name[] immediately following TypeInfo_Enum 1063 dtb.nbytes(cast(uint)(namelen + 1), name); 1064 } 1065 1066 override void visit(TypeInfoPointerDeclaration d) 1067 { 1068 //printf("TypeInfoPointerDeclaration.toDt()\n"); 1069 verifyStructSize(Type.typeinfopointer, 3 * target.ptrsize); 1070 1071 dtb.xoff(toVtblSymbol(Type.typeinfopointer), 0); // vtbl for TypeInfo_Pointer 1072 if (Type.typeinfopointer.hasMonitor()) 1073 dtb.size(0); // monitor 1074 1075 auto tc = d.tinfo.isTypePointer(); 1076 1077 genTypeInfo(d.loc, tc.next, null); 1078 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for type being pointed to 1079 } 1080 1081 override void visit(TypeInfoArrayDeclaration d) 1082 { 1083 //printf("TypeInfoArrayDeclaration.toDt()\n"); 1084 verifyStructSize(Type.typeinfoarray, 3 * target.ptrsize); 1085 1086 dtb.xoff(toVtblSymbol(Type.typeinfoarray), 0); // vtbl for TypeInfo_Array 1087 if (Type.typeinfoarray.hasMonitor()) 1088 dtb.size(0); // monitor 1089 1090 auto tc = d.tinfo.isTypeDArray(); 1091 1092 genTypeInfo(d.loc, tc.next, null); 1093 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for array of type 1094 } 1095 1096 override void visit(TypeInfoStaticArrayDeclaration d) 1097 { 1098 //printf("TypeInfoStaticArrayDeclaration.toDt()\n"); 1099 verifyStructSize(Type.typeinfostaticarray, 4 * target.ptrsize); 1100 1101 dtb.xoff(toVtblSymbol(Type.typeinfostaticarray), 0); // vtbl for TypeInfo_StaticArray 1102 if (Type.typeinfostaticarray.hasMonitor()) 1103 dtb.size(0); // monitor 1104 1105 auto tc = d.tinfo.isTypeSArray(); 1106 1107 genTypeInfo(d.loc, tc.next, null); 1108 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for array of type 1109 1110 dtb.size(tc.dim.toInteger()); // length 1111 } 1112 1113 override void visit(TypeInfoVectorDeclaration d) 1114 { 1115 //printf("TypeInfoVectorDeclaration.toDt()\n"); 1116 verifyStructSize(Type.typeinfovector, 3 * target.ptrsize); 1117 1118 dtb.xoff(toVtblSymbol(Type.typeinfovector), 0); // vtbl for TypeInfo_Vector 1119 if (Type.typeinfovector.hasMonitor()) 1120 dtb.size(0); // monitor 1121 1122 auto tc = d.tinfo.isTypeVector(); 1123 1124 genTypeInfo(d.loc, tc.basetype, null); 1125 dtb.xoff(toSymbol(tc.basetype.vtinfo), 0); // TypeInfo for equivalent static array 1126 } 1127 1128 override void visit(TypeInfoAssociativeArrayDeclaration d) 1129 { 1130 //printf("TypeInfoAssociativeArrayDeclaration.toDt()\n"); 1131 verifyStructSize(Type.typeinfoassociativearray, 4 * target.ptrsize); 1132 1133 dtb.xoff(toVtblSymbol(Type.typeinfoassociativearray), 0); // vtbl for TypeInfo_AssociativeArray 1134 if (Type.typeinfoassociativearray.hasMonitor()) 1135 dtb.size(0); // monitor 1136 1137 auto tc = d.tinfo.isTypeAArray(); 1138 1139 genTypeInfo(d.loc, tc.next, null); 1140 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for array of type 1141 1142 genTypeInfo(d.loc, tc.index, null); 1143 dtb.xoff(toSymbol(tc.index.vtinfo), 0); // TypeInfo for array of type 1144 } 1145 1146 override void visit(TypeInfoFunctionDeclaration d) 1147 { 1148 //printf("TypeInfoFunctionDeclaration.toDt()\n"); 1149 verifyStructSize(Type.typeinfofunction, 5 * target.ptrsize); 1150 1151 dtb.xoff(toVtblSymbol(Type.typeinfofunction), 0); // vtbl for TypeInfo_Function 1152 if (Type.typeinfofunction.hasMonitor()) 1153 dtb.size(0); // monitor 1154 1155 auto tc = d.tinfo.isTypeFunction(); 1156 1157 genTypeInfo(d.loc, tc.next, null); 1158 dtb.xoff(toSymbol(tc.next.vtinfo), 0); // TypeInfo for function return value 1159 1160 const name = d.tinfo.deco; 1161 assert(name); 1162 const namelen = strlen(name); 1163 dtb.size(namelen); 1164 dtb.xoff(d.csym, Type.typeinfofunction.structsize); 1165 1166 // Put out name[] immediately following TypeInfo_Function 1167 dtb.nbytes(cast(uint)(namelen + 1), name); 1168 } 1169 1170 override void visit(TypeInfoDelegateDeclaration d) 1171 { 1172 //printf("TypeInfoDelegateDeclaration.toDt()\n"); 1173 verifyStructSize(Type.typeinfodelegate, 5 * target.ptrsize); 1174 1175 dtb.xoff(toVtblSymbol(Type.typeinfodelegate), 0); // vtbl for TypeInfo_Delegate 1176 if (Type.typeinfodelegate.hasMonitor()) 1177 dtb.size(0); // monitor 1178 1179 auto tc = d.tinfo.isTypeDelegate(); 1180 1181 genTypeInfo(d.loc, tc.next.nextOf(), null); 1182 dtb.xoff(toSymbol(tc.next.nextOf().vtinfo), 0); // TypeInfo for delegate return value 1183 1184 const name = d.tinfo.deco; 1185 assert(name); 1186 const namelen = strlen(name); 1187 dtb.size(namelen); 1188 dtb.xoff(d.csym, Type.typeinfodelegate.structsize); 1189 1190 // Put out name[] immediately following TypeInfo_Delegate 1191 dtb.nbytes(cast(uint)(namelen + 1), name); 1192 } 1193 1194 override void visit(TypeInfoStructDeclaration d) 1195 { 1196 //printf("TypeInfoStructDeclaration.toDt() '%s'\n", d.toChars()); 1197 if (global.params.is64bit) 1198 verifyStructSize(Type.typeinfostruct, 17 * target.ptrsize); 1199 else 1200 verifyStructSize(Type.typeinfostruct, 15 * target.ptrsize); 1201 1202 dtb.xoff(toVtblSymbol(Type.typeinfostruct), 0); // vtbl for TypeInfo_Struct 1203 if (Type.typeinfostruct.hasMonitor()) 1204 dtb.size(0); // monitor 1205 1206 auto tc = d.tinfo.isTypeStruct(); 1207 StructDeclaration sd = tc.sym; 1208 1209 if (!sd.members) 1210 return; 1211 1212 if (TemplateInstance ti = sd.isInstantiated()) 1213 { 1214 if (!ti.needsCodegen()) 1215 { 1216 assert(ti.minst || sd.requestTypeInfo); 1217 1218 /* ti.toObjFile() won't get called. So, store these 1219 * member functions into object file in here. 1220 */ 1221 if (sd.xeq && sd.xeq != StructDeclaration.xerreq) 1222 toObjFile(sd.xeq, global.params.multiobj); 1223 if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp) 1224 toObjFile(sd.xcmp, global.params.multiobj); 1225 if (FuncDeclaration ftostr = search_toString(sd)) 1226 toObjFile(ftostr, global.params.multiobj); 1227 if (sd.xhash) 1228 toObjFile(sd.xhash, global.params.multiobj); 1229 if (sd.postblit) 1230 toObjFile(sd.postblit, global.params.multiobj); 1231 if (sd.dtor) 1232 toObjFile(sd.dtor, global.params.multiobj); 1233 } 1234 } 1235 1236 /* Put out: 1237 * char[] name; 1238 * void[] init; 1239 * hash_t function(in void*) xtoHash; 1240 * bool function(in void*, in void*) xopEquals; 1241 * int function(in void*, in void*) xopCmp; 1242 * string function(const(void)*) xtoString; 1243 * StructFlags m_flags; 1244 * //xgetMembers; 1245 * xdtor; 1246 * xpostblit; 1247 * uint m_align; 1248 * version (X86_64) 1249 * TypeInfo m_arg1; 1250 * TypeInfo m_arg2; 1251 * xgetRTInfo 1252 */ 1253 1254 const name = sd.toPrettyChars(); 1255 const namelen = strlen(name); 1256 dtb.size(namelen); 1257 dtb.xoff(d.csym, Type.typeinfostruct.structsize); 1258 1259 // void[] init; 1260 dtb.size(sd.structsize); // init.length 1261 if (sd.zeroInit) 1262 dtb.size(0); // null for 0 initialization 1263 else 1264 dtb.xoff(toInitializer(sd), 0); // init.ptr 1265 1266 if (FuncDeclaration fd = sd.xhash) 1267 { 1268 dtb.xoff(toSymbol(fd), 0); 1269 TypeFunction tf = cast(TypeFunction)fd.type; 1270 assert(tf.ty == Tfunction); 1271 /* I'm a little unsure this is the right way to do it. Perhaps a better 1272 * way would to automatically add these attributes to any struct member 1273 * function with the name "toHash". 1274 * So I'm leaving this here as an experiment for the moment. 1275 */ 1276 if (!tf.isnothrow || tf.trust == TRUST.system /*|| tf.purity == PURE.impure*/) 1277 warning(fd.loc, "toHash() must be declared as extern (D) size_t toHash() const nothrow @safe, not %s", tf.toChars()); 1278 } 1279 else 1280 dtb.size(0); 1281 1282 if (sd.xeq) 1283 dtb.xoff(toSymbol(sd.xeq), 0); 1284 else 1285 dtb.size(0); 1286 1287 if (sd.xcmp) 1288 dtb.xoff(toSymbol(sd.xcmp), 0); 1289 else 1290 dtb.size(0); 1291 1292 if (FuncDeclaration fd = search_toString(sd)) 1293 { 1294 dtb.xoff(toSymbol(fd), 0); 1295 } 1296 else 1297 dtb.size(0); 1298 1299 // StructFlags m_flags; 1300 StructFlags m_flags = StructFlags.none; 1301 if (tc.hasPointers()) m_flags |= StructFlags.hasPointers; 1302 dtb.size(m_flags); 1303 1304 version (none) 1305 { 1306 // xgetMembers 1307 if (auto sgetmembers = sd.findGetMembers()) 1308 dtb.xoff(toSymbol(sgetmembers), 0); 1309 else 1310 dtb.size(0); // xgetMembers 1311 } 1312 1313 // xdtor 1314 if (auto sdtor = sd.tidtor) 1315 dtb.xoff(toSymbol(sdtor), 0); 1316 else 1317 dtb.size(0); // xdtor 1318 1319 // xpostblit 1320 FuncDeclaration spostblit = sd.postblit; 1321 if (spostblit && !(spostblit.storage_class & STC.disable)) 1322 dtb.xoff(toSymbol(spostblit), 0); 1323 else 1324 dtb.size(0); // xpostblit 1325 1326 // uint m_align; 1327 dtb.size(tc.alignsize()); 1328 1329 if (global.params.is64bit) 1330 { 1331 Type t = sd.arg1type; 1332 foreach (i; 0 .. 2) 1333 { 1334 // m_argi 1335 if (t) 1336 { 1337 genTypeInfo(d.loc, t, null); 1338 dtb.xoff(toSymbol(t.vtinfo), 0); 1339 } 1340 else 1341 dtb.size(0); 1342 1343 t = sd.arg2type; 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 }