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