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, %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 }