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 }