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