1 /**
2  * Convert an AST that went through all semantic phases into an object file.
3  *
4  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/tocsym.d, _toobj.d)
8  * Documentation:  https://dlang.org/phobos/dmd_toobj.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/toobj.d
10  */
11 
12 module dmd.toobj;
13 
14 import core.stdc.stdio;
15 import core.stdc.stddef;
16 import core.stdc.string;
17 import core.stdc.time;
18 
19 import dmd.root.array;
20 import dmd.common.outbuffer;
21 import dmd.root.rmem;
22 import dmd.root.rootobject;
23 
24 import dmd.aggregate;
25 import dmd.arraytypes;
26 import dmd.astenums;
27 import dmd.attrib;
28 import dmd.dclass;
29 import dmd.declaration;
30 import dmd.denum;
31 import dmd.dmdparams;
32 import dmd.dmodule;
33 import dmd.dscope;
34 import dmd.dstruct;
35 import dmd.dsymbol;
36 import dmd.dtemplate;
37 import dmd.errors;
38 import dmd.expression;
39 import dmd.func;
40 import dmd.globals;
41 import dmd.glue;
42 import dmd.hdrgen;
43 import dmd.id;
44 import dmd.init;
45 import dmd.location;
46 import dmd.mtype;
47 import dmd.nspace;
48 import dmd.objc_glue;
49 import dmd.statement;
50 import dmd.staticassert;
51 import dmd.target;
52 import dmd.tocsym;
53 import dmd.toctype;
54 import dmd.tocvdebug;
55 import dmd.todt;
56 import dmd.tokens;
57 import dmd.traits;
58 import dmd.typinf;
59 import dmd.visitor;
60 
61 import dmd.backend.cc;
62 import dmd.backend.cdef;
63 import dmd.backend.cgcv;
64 import dmd.backend.code;
65 import dmd.backend.code_x86;
66 import dmd.backend.cv4;
67 import dmd.backend.dt;
68 import dmd.backend.el;
69 import dmd.backend.global;
70 import dmd.backend.obj;
71 import dmd.backend.oper;
72 import dmd.backend.ty;
73 import dmd.backend.type;
74 
75 extern (C++):
76 
77 alias toSymbol = dmd.tocsym.toSymbol;
78 alias toSymbol = dmd.glue.toSymbol;
79 
80 
81 /* ================================================================== */
82 
83 // Put out instance of ModuleInfo for this Module
84 
85 void genModuleInfo(Module m)
86 {
87     //printf("Module.genmoduleinfo() %s\n", m.toChars());
88 
89     if (!Module.moduleinfo)
90     {
91         ObjectNotFound(Id.ModuleInfo);
92     }
93 
94     Symbol *msym = toSymbol(m);
95 
96     //////////////////////////////////////////////
97 
98     m.csym.Sclass = SC.global;
99     m.csym.Sfl = FLdata;
100 
101     auto dtb = DtBuilder(0);
102 
103     ClassDeclarations aclasses;
104     getLocalClasses(m, aclasses);
105 
106     // importedModules[]
107     size_t aimports_dim = m.aimports.length;
108     for (size_t i = 0; i < m.aimports.length; i++)
109     {
110         Module mod = m.aimports[i];
111         if (!mod.needmoduleinfo)
112             aimports_dim--;
113     }
114 
115     FuncDeclaration sgetmembers = m.findGetMembers();
116 
117     // These must match the values in druntime/src/object_.d
118     enum
119     {
120         MIstandalone      = 0x4,
121         MItlsctor         = 0x8,
122         MItlsdtor         = 0x10,
123         MIctor            = 0x20,
124         MIdtor            = 0x40,
125         MIxgetMembers     = 0x80,
126         MIictor           = 0x100,
127         MIunitTest        = 0x200,
128         MIimportedModules = 0x400,
129         MIlocalClasses    = 0x800,
130         MIname            = 0x1000,
131     }
132 
133     uint flags = 0;
134     if (!m.needmoduleinfo)
135         flags |= MIstandalone;
136     if (m.sctor)
137         flags |= MItlsctor;
138     if (m.sdtor)
139         flags |= MItlsdtor;
140     if (m.ssharedctor)
141         flags |= MIctor;
142     if (m.sshareddtor)
143         flags |= MIdtor;
144     if (sgetmembers)
145         flags |= MIxgetMembers;
146     if (m.sictor)
147         flags |= MIictor;
148     if (m.stest)
149         flags |= MIunitTest;
150     if (aimports_dim)
151         flags |= MIimportedModules;
152     if (aclasses.length)
153         flags |= MIlocalClasses;
154     flags |= MIname;
155 
156     dtb.dword(flags);        // _flags
157     dtb.dword(0);            // _index
158 
159     if (flags & MItlsctor)
160         dtb.xoff(m.sctor, 0, TYnptr);
161     if (flags & MItlsdtor)
162         dtb.xoff(m.sdtor, 0, TYnptr);
163     if (flags & MIctor)
164         dtb.xoff(m.ssharedctor, 0, TYnptr);
165     if (flags & MIdtor)
166         dtb.xoff(m.sshareddtor, 0, TYnptr);
167     if (flags & MIxgetMembers)
168         dtb.xoff(toSymbol(sgetmembers), 0, TYnptr);
169     if (flags & MIictor)
170         dtb.xoff(m.sictor, 0, TYnptr);
171     if (flags & MIunitTest)
172         dtb.xoff(m.stest, 0, TYnptr);
173     if (flags & MIimportedModules)
174     {
175         dtb.size(aimports_dim);
176         foreach (i; 0 .. m.aimports.length)
177         {
178             Module mod = m.aimports[i];
179 
180             if (!mod.needmoduleinfo)
181                 continue;
182 
183             Symbol *s = toSymbol(mod);
184 
185             /* Weak references don't pull objects in from the library,
186              * they resolve to 0 if not pulled in by something else.
187              * Don't pull in a module just because it was imported.
188              */
189             s.Sflags |= SFLweak;
190             dtb.xoff(s, 0, TYnptr);
191         }
192     }
193     if (flags & MIlocalClasses)
194     {
195         dtb.size(aclasses.length);
196         foreach (i; 0 .. aclasses.length)
197         {
198             ClassDeclaration cd = aclasses[i];
199             dtb.xoff(toSymbol(cd), 0, TYnptr);
200         }
201     }
202     if (flags & MIname)
203     {
204         // Put out module name as a 0-terminated string, to save bytes
205         m.nameoffset = dtb.length();
206         const(char) *name = m.toPrettyChars();
207         m.namelen = strlen(name);
208         dtb.nbytes(cast(uint)m.namelen + 1, name);
209         //printf("nameoffset = x%x\n", nameoffset);
210     }
211 
212     objc.generateModuleInfo(m);
213     m.csym.Sdt = dtb.finish();
214     out_readonly(m.csym);
215     outdata(m.csym);
216 
217     //////////////////////////////////////////////
218 
219     objmod.moduleinfo(msym);
220 }
221 
222 /*****************************************
223  * write pointer references for typed data to the object file
224  * a class type is considered to mean a reference to a class instance
225  * Params:
226  *      type   = type of the data to check for pointers
227  *      s      = symbol that contains the data
228  *      offset = offset of the data inside the Symbol's memory
229  */
230 void write_pointers(Type type, Symbol *s, uint offset)
231 {
232     uint ty = type.toBasetype().ty;
233     if (ty == Tclass)
234         return objmod.write_pointerRef(s, offset);
235 
236     write_instance_pointers(type, s, offset);
237 }
238 
239 /*****************************************
240 * write pointer references for typed data to the object file
241 * a class type is considered to mean the instance, not a reference
242 * Params:
243 *      type   = type of the data to check for pointers
244 *      s      = symbol that contains the data
245 *      offset = offset of the data inside the Symbol's memory
246 */
247 void write_instance_pointers(Type type, Symbol *s, uint offset)
248 {
249     if (!type.hasPointers())
250         return;
251 
252     Array!(ulong) data;
253     ulong sz = getTypePointerBitmap(Loc.initial, type, &data);
254     if (sz == ulong.max)
255         return;
256 
257     const bytes_size_t = cast(size_t)Type.tsize_t.size(Loc.initial);
258     const bits_size_t = bytes_size_t * 8;
259     auto words = cast(size_t)(sz / bytes_size_t);
260     for (size_t i = 0; i < data.length; i++)
261     {
262         size_t bits = words < bits_size_t ? words : bits_size_t;
263         for (size_t b = 0; b < bits; b++)
264             if (data[i] & (1L << b))
265             {
266                 auto off = cast(uint) ((i * bits_size_t + b) * bytes_size_t);
267                 objmod.write_pointerRef(s, off + offset);
268             }
269         words -= bits;
270     }
271 }
272 
273 /* ================================================================== */
274 
275 void toObjFile(Dsymbol ds, bool multiobj)
276 {
277     //printf("toObjFile(%s %s)\n", ds.kind(), ds.toChars());
278 
279     bool isCfile = ds.isCsymbol();
280 
281     extern (C++) final class ToObjFile : Visitor
282     {
283         alias visit = Visitor.visit;
284     public:
285         bool multiobj;
286 
287         this(bool multiobj) scope
288         {
289             this.multiobj = multiobj;
290         }
291 
292         void visitNoMultiObj(Dsymbol ds)
293         {
294             bool multiobjsave = multiobj;
295             multiobj = false;
296             ds.accept(this);
297             multiobj = multiobjsave;
298         }
299 
300         override void visit(Dsymbol ds)
301         {
302             //printf("Dsymbol.toObjFile('%s')\n", ds.toChars());
303             // ignore
304         }
305 
306         override void visit(FuncDeclaration fd)
307         {
308             // in glue.c
309             FuncDeclaration_toObjFile(fd, multiobj);
310         }
311 
312         override void visit(ClassDeclaration cd)
313         {
314             //printf("ClassDeclaration.toObjFile('%s')\n", cd.toChars());
315 
316             if (cd.type.ty == Terror)
317             {
318                 cd.error("had semantic errors when compiling");
319                 return;
320             }
321 
322             if (!cd.members)
323                 return;
324 
325             if (multiobj && !cd.hasStaticCtorOrDtor())
326             {
327                 obj_append(cd);
328                 return;
329             }
330 
331             if (driverParams.symdebugref)
332                 Type_toCtype(cd.type); // calls toDebug() only once
333             else if (driverParams.symdebug)
334                 toDebug(cd);
335 
336             assert(cd.semanticRun >= PASS.semantic3done);     // semantic() should have been run to completion
337 
338             SC scclass = SC.comdat;
339 
340             // Put out the members
341             /* There might be static ctors in the members, and they cannot
342              * be put in separate obj files.
343              */
344             cd.members.foreachDsymbol( (s) { s.accept(this); } );
345 
346             if (cd.classKind == ClassKind.objc)
347             {
348                 objc.toObjFile(cd);
349                 return;
350             }
351 
352             // If something goes wrong during this pass don't bother with the
353             // rest as we may have incomplete info
354             // https://issues.dlang.org/show_bug.cgi?id=17918
355             if (!finishVtbl(cd))
356             {
357                 return;
358             }
359 
360             const bool gentypeinfo = global.params.useTypeInfo && Type.dtypeinfo;
361             const bool genclassinfo = gentypeinfo || !(cd.isCPPclass || cd.isCOMclass);
362 
363             // Generate C symbols
364             if (genclassinfo)
365                 toSymbol(cd);                           // __ClassZ symbol
366             toVtblSymbol(cd, genclassinfo);             // __vtblZ symbol
367             Symbol *sinit = toInitializer(cd);          // __initZ symbol
368 
369             //////////////////////////////////////////////
370 
371             // Generate static initializer
372             {
373                 sinit.Sclass = scclass;
374                 sinit.Sfl = FLdata;
375                 auto dtb = DtBuilder(0);
376                 ClassDeclaration_toDt(cd, dtb);
377                 sinit.Sdt = dtb.finish();
378                 out_readonly(sinit);
379                 outdata(sinit);
380             }
381 
382             //////////////////////////////////////////////
383 
384             // Put out the TypeInfo
385             if (gentypeinfo)
386                 genTypeInfo(null, cd.loc, cd.type, null);
387             //toObjFile(cd.type.vtinfo, multiobj);
388 
389             if (genclassinfo)
390             {
391                 genClassInfoForClass(cd, sinit);
392             }
393 
394             //////////////////////////////////////////////
395 
396             // Put out the vtbl[]
397             //printf("putting out %s.vtbl[]\n", toChars());
398             auto dtbv = DtBuilder(0);
399             if (cd.vtblOffset())
400                 dtbv.xoff(cd.csym, 0, TYnptr);           // first entry is ClassInfo reference
401             foreach (i; cd.vtblOffset() .. cd.vtbl.length)
402             {
403                 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
404 
405                 //printf("\tvtbl[%d] = %p\n", i, fd);
406                 if (fd && (fd.fbody || !cd.isAbstract()))
407                 {
408                     dtbv.xoff(toSymbol(fd), 0, TYnptr);
409                 }
410                 else
411                     dtbv.size(0);
412             }
413             if (dtbv.isZeroLength())
414             {
415                 /* Someone made an 'extern (C++) class C { }' with no virtual functions.
416                  * But making an empty vtbl[] causes linking problems, so make a dummy
417                  * entry.
418                  */
419                 dtbv.size(0);
420             }
421             cd.vtblsym.csym.Sdt = dtbv.finish();
422             cd.vtblsym.csym.Sclass = scclass;
423             cd.vtblsym.csym.Sfl = FLdata;
424             out_readonly(cd.vtblsym.csym);
425             outdata(cd.vtblsym.csym);
426             if (cd.isExport())
427                 objmod.export_symbol(cd.vtblsym.csym,0);
428         }
429 
430         override void visit(InterfaceDeclaration id)
431         {
432             //printf("InterfaceDeclaration.toObjFile('%s')\n", id.toChars());
433 
434             if (id.type.ty == Terror)
435             {
436                 id.error("had semantic errors when compiling");
437                 return;
438             }
439 
440             if (!id.members)
441                 return;
442 
443             if (driverParams.symdebugref)
444                 Type_toCtype(id.type); // calls toDebug() only once
445             else if (driverParams.symdebug)
446                 toDebug(id);
447 
448             // Put out the members
449             id.members.foreachDsymbol( (s) { visitNoMultiObj(s); } );
450 
451             // Objetive-C protocols are only output if implemented as a class.
452             // If so, they're output via the class declaration.
453             if (id.classKind == ClassKind.objc)
454                 return;
455 
456             const bool gentypeinfo = global.params.useTypeInfo && Type.dtypeinfo;
457             const bool genclassinfo = gentypeinfo || !(id.isCPPclass || id.isCOMclass);
458 
459 
460             // Generate C symbols
461             if (genclassinfo)
462                 toSymbol(id);
463 
464             //////////////////////////////////////////////
465 
466             // Put out the TypeInfo
467             if (gentypeinfo)
468             {
469                 genTypeInfo(null, id.loc, id.type, null);
470                 id.type.vtinfo.accept(this);
471             }
472 
473             //////////////////////////////////////////////
474 
475             if (genclassinfo)
476                 genClassInfoForInterface(id);
477         }
478 
479         override void visit(StructDeclaration sd)
480         {
481             //printf("StructDeclaration.toObjFile('%s')\n", sd.toChars());
482 
483             if (sd.type.ty == Terror)
484             {
485                 sd.error("had semantic errors when compiling");
486                 return;
487             }
488 
489             if (multiobj && !sd.hasStaticCtorOrDtor())
490             {
491                 obj_append(sd);
492                 return;
493             }
494 
495             // Anonymous structs/unions only exist as part of others,
496             // do not output forward referenced structs's
497             if (!sd.isAnonymous() && sd.members)
498             {
499                 if (driverParams.symdebugref)
500                     Type_toCtype(sd.type); // calls toDebug() only once
501                 else if (driverParams.symdebug)
502                     toDebug(sd);
503 
504                 if (global.params.useTypeInfo && Type.dtypeinfo)
505                     genTypeInfo(null, sd.loc, sd.type, null);
506 
507                 // Generate static initializer
508                 auto sinit = toInitializer(sd);
509                 if (sinit.Sclass == SC.extern_)
510                 {
511                     if (sinit == bzeroSymbol) assert(0);
512                     sinit.Sclass = sd.isInstantiated() ? SC.comdat : SC.global;
513                     sinit.Sfl = FLdata;
514                     auto dtb = DtBuilder(0);
515                     StructDeclaration_toDt(sd, dtb);
516                     sinit.Sdt = dtb.finish();
517 
518                     /* fails to link on OBJ_MACH 64 with:
519                      *  ld: in generated/osx/release/64/libphobos2.a(dwarfeh_8dc_56a.o),
520                      *  in section __TEXT,__textcoal_nt reloc 6:
521                      *  symbol index out of range for architecture x86_64
522                      */
523                     if (config.objfmt != OBJ_MACH &&
524                         dtallzeros(sinit.Sdt))
525                     {
526                         sinit.Sclass = SC.global;
527                         dt2common(&sinit.Sdt);
528                     }
529                     else
530                         out_readonly(sinit);    // put in read-only segment
531                     outdata(sinit);
532                 }
533 
534                 // Put out the members
535                 /* There might be static ctors in the members, and they cannot
536                  * be put in separate obj files.
537                  */
538                 sd.members.foreachDsymbol( (s) { s.accept(this); } );
539 
540                 if (sd.xeq && sd.xeq != StructDeclaration.xerreq)
541                     sd.xeq.accept(this);
542                 if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp)
543                     sd.xcmp.accept(this);
544                 if (sd.xhash)
545                     sd.xhash.accept(this);
546             }
547         }
548 
549         override void visit(VarDeclaration vd)
550         {
551 
552             //printf("VarDeclaration.toObjFile(%p '%s' type=%s) visibility %d\n", vd, vd.toChars(), vd.type.toChars(), vd.visibility);
553             //printf("\talign = %d\n", vd.alignment);
554 
555             if (vd.type.ty == Terror)
556             {
557                 vd.error("had semantic errors when compiling");
558                 return;
559             }
560 
561             if (vd.aliasTuple)
562             {
563                 vd.toAlias().accept(this);
564                 return;
565             }
566 
567             // Do not store variables we cannot take the address of
568             if (!vd.canTakeAddressOf())
569             {
570                 return;
571             }
572 
573             if (!vd.isDataseg() || vd.storage_class & STC.extern_)
574                 return;
575 
576             Symbol *s = toSymbol(vd);
577             const sz64 = vd.type.size(vd.loc);
578             if (sz64 == SIZE_INVALID)
579             {
580                 vd.error("size overflow");
581                 return;
582             }
583             if (sz64 > target.maxStaticDataSize)
584             {
585                 vd.error("size of 0x%llx exceeds max allowed size 0x%llx", sz64, target.maxStaticDataSize);
586             }
587             uint sz = cast(uint)sz64;
588 
589             Dsymbol parent = vd.toParent();
590             s.Sclass = SC.global;
591 
592             /* Make C static functions SCstatic
593              */
594             if (vd.storage_class & STC.static_ && vd.isCsymbol())
595                 s.Sclass = SC.static_;
596 
597             do
598             {
599                 /* Global template data members need to be in comdat's
600                  * in case multiple .obj files instantiate the same
601                  * template with the same types.
602                  */
603                 if (parent.isTemplateInstance() && !parent.isTemplateMixin())
604                 {
605                     s.Sclass = SC.comdat;
606                     break;
607                 }
608                 parent = parent.parent;
609             } while (parent);
610             s.Sfl = FLdata;
611 
612             // Size 0 should only be possible for T[0] and noreturn
613             if (!sz)
614             {
615                 const ty = vd.type.toBasetype().ty;
616                 if (ty != Tsarray && ty != Tnoreturn && !vd.isCsymbol())
617                     assert(0); // this shouldn't be possible
618             }
619 
620             auto dtb = DtBuilder(0);
621             if (config.objfmt == OBJ_MACH && target.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread)
622             {
623                 tlsToDt(vd, s, sz, dtb, isCfile);
624             }
625             else if (!sz)
626             {
627                 /* Give it a byte of data
628                  * so we can take the 'address' of this symbol
629                  * and avoid problematic behavior of object file format
630                  * Note that gcc will give 0 size C objects a `comm a:byte:00h`
631                  */
632                 dtb.nzeros(1);
633             }
634             else if (vd._init)
635             {
636                 initializerToDt(vd, dtb, vd.isCsymbol());
637             }
638             else
639             {
640                 Type_toDt(vd.type, dtb, vd.isCsymbol());
641             }
642             s.Sdt = dtb.finish();
643 
644             // See if we can convert a comdat to a comdef,
645             // which saves on exe file space.
646             if (s.Sclass == SC.comdat &&
647                 s.Sdt &&
648                 dtallzeros(s.Sdt) &&
649                 !vd.isThreadlocal())
650             {
651                 s.Sclass = SC.global;
652                 dt2common(&s.Sdt);
653             }
654 
655             if (s.Sclass == SC.global && s.Stype.Tty & mTYconst)
656                 out_readonly(s);
657 
658             outdata(s);
659             if (vd.type.isMutable() || !vd._init)
660                 write_pointers(vd.type, s, 0);
661             if (vd.isExport())
662                 objmod.export_symbol(s, 0);
663         }
664 
665         override void visit(EnumDeclaration ed)
666         {
667             if (ed.semanticRun >= PASS.obj)  // already written
668                 return;
669             //printf("EnumDeclaration.toObjFile('%s')\n", ed.toChars());
670 
671             if (ed.errors || ed.type.ty == Terror)
672             {
673                 ed.error("had semantic errors when compiling");
674                 return;
675             }
676 
677             if (ed.isAnonymous())
678                 return;
679 
680             if (driverParams.symdebugref)
681                 Type_toCtype(ed.type); // calls toDebug() only once
682             else if (driverParams.symdebug)
683                 toDebug(ed);
684 
685             if (global.params.useTypeInfo && Type.dtypeinfo)
686                 genTypeInfo(null, ed.loc, ed.type, null);
687 
688             TypeEnum tc = cast(TypeEnum)ed.type;
689             if (!tc.sym.members || ed.type.isZeroInit(Loc.initial))
690             {
691             }
692             else
693             {
694                 SC scclass = SC.global;
695                 if (ed.isInstantiated())
696                     scclass = SC.comdat;
697 
698                 // Generate static initializer
699                 toInitializer(ed);
700                 ed.sinit.Sclass = scclass;
701                 ed.sinit.Sfl = FLdata;
702                 auto dtb = DtBuilder(0);
703                 Expression_toDt(tc.sym.defaultval, dtb);
704                 ed.sinit.Sdt = dtb.finish();
705                 outdata(ed.sinit);
706             }
707             ed.semanticRun = PASS.obj;
708         }
709 
710         override void visit(TypeInfoDeclaration tid)
711         {
712             if (isSpeculativeType(tid.tinfo))
713             {
714                 //printf("-speculative '%s'\n", tid.toPrettyChars());
715                 return;
716             }
717             //printf("TypeInfoDeclaration.toObjFile(%p '%s') visibility %d\n", tid, tid.toChars(), tid.visibility);
718 
719             if (multiobj)
720             {
721                 obj_append(tid);
722                 return;
723             }
724 
725             Symbol *s = toSymbol(tid);
726             s.Sclass = SC.comdat;
727             s.Sfl = FLdata;
728 
729             auto dtb = DtBuilder(0);
730             TypeInfo_toDt(dtb, tid);
731             s.Sdt = dtb.finish();
732 
733             // See if we can convert a comdat to a comdef,
734             // which saves on exe file space.
735             if (s.Sclass == SC.comdat &&
736                 dtallzeros(s.Sdt))
737             {
738                 s.Sclass = SC.global;
739                 dt2common(&s.Sdt);
740             }
741 
742             outdata(s);
743             if (tid.isExport())
744                 objmod.export_symbol(s, 0);
745         }
746 
747         override void visit(AttribDeclaration ad)
748         {
749             Dsymbols *d = ad.include(null);
750 
751             if (d)
752             {
753                 for (size_t i = 0; i < d.length; i++)
754                 {
755                     Dsymbol s = (*d)[i];
756                     s.accept(this);
757                 }
758             }
759         }
760 
761         override void visit(PragmaDeclaration pd)
762         {
763             if (pd.ident == Id.lib)
764             {
765                 assert(pd.args && pd.args.length == 1);
766 
767                 Expression e = (*pd.args)[0];
768 
769                 assert(e.op == EXP.string_);
770 
771                 StringExp se = cast(StringExp)e;
772                 char *name = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1);
773                 se.writeTo(name, true);
774 
775                 /* Embed the library names into the object file.
776                  * The linker will then automatically
777                  * search that library, too.
778                  */
779                 if (!obj_includelib(name))
780                 {
781                     /* The format does not allow embedded library names,
782                      * so instead append the library name to the list to be passed
783                      * to the linker.
784                      */
785                     global.params.libfiles.push(name);
786                 }
787             }
788             else if (pd.ident == Id.startaddress)
789             {
790                 assert(pd.args && pd.args.length == 1);
791                 Expression e = (*pd.args)[0];
792                 Dsymbol sa = getDsymbol(e);
793                 FuncDeclaration f = sa.isFuncDeclaration();
794                 assert(f);
795                 Symbol *s = toSymbol(f);
796                 obj_startaddress(s);
797             }
798             else if (pd.ident == Id.linkerDirective)
799             {
800                 assert(pd.args && pd.args.length == 1);
801 
802                 Expression e = (*pd.args)[0];
803 
804                 assert(e.op == EXP.string_);
805 
806                 StringExp se = cast(StringExp)e;
807                 char *directive = cast(char *)mem.xmalloc(se.numberOfCodeUnits() + 1);
808                 se.writeTo(directive, true);
809 
810                 obj_linkerdirective(directive);
811             }
812 
813             visit(cast(AttribDeclaration)pd);
814         }
815 
816         override void visit(TemplateInstance ti)
817         {
818             //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toChars());
819             if (!isError(ti) && ti.members)
820             {
821                 if (!ti.needsCodegen())
822                 {
823                     //printf("-speculative (%p, %s)\n", ti, ti.toPrettyChars());
824                     return;
825                 }
826                 //printf("TemplateInstance.toObjFile(%p, '%s')\n", ti, ti.toPrettyChars());
827 
828                 if (multiobj)
829                 {
830                     // Append to list of object files to be written later
831                     obj_append(ti);
832                 }
833                 else
834                 {
835                     ti.members.foreachDsymbol( (s) { s.accept(this); } );
836                 }
837             }
838         }
839 
840         override void visit(TemplateMixin tm)
841         {
842             //printf("TemplateMixin.toObjFile('%s')\n", tm.toChars());
843             if (!isError(tm))
844             {
845                 tm.members.foreachDsymbol( (s) { s.accept(this); } );
846             }
847         }
848 
849         override void visit(StaticAssert sa)
850         {
851         }
852 
853         override void visit(Nspace ns)
854         {
855             //printf("Nspace.toObjFile('%s', this = %p)\n", ns.toChars(), ns);
856             if (!isError(ns) && ns.members)
857             {
858                 if (multiobj)
859                 {
860                     // Append to list of object files to be written later
861                     obj_append(ns);
862                 }
863                 else
864                 {
865                     ns.members.foreachDsymbol( (s) { s.accept(this); } );
866                 }
867             }
868         }
869 
870         override void visit(TupleDeclaration tup)
871         {
872             tup.foreachVar((s) { s.accept(this); });
873         }
874 
875     private:
876         static void initializerToDt(VarDeclaration vd, ref DtBuilder dtb, bool isCfile)
877         {
878             Initializer_toDt(vd._init, dtb, isCfile);
879 
880             // Look for static array that is block initialized
881             ExpInitializer ie = vd._init.isExpInitializer();
882 
883             Type tb = vd.type.toBasetype();
884             if (tb.ty == Tsarray && ie &&
885                 !tb.nextOf().equals(ie.exp.type.toBasetype().nextOf()) &&
886                 ie.exp.implicitConvTo(tb.nextOf())
887                 )
888             {
889                 auto dim = (cast(TypeSArray)tb).dim.toInteger();
890 
891                 // Duplicate Sdt 'dim-1' times, as we already have the first one
892                 while (--dim > 0)
893                 {
894                     Expression_toDt(ie.exp, dtb);
895                 }
896             }
897         }
898 
899         /**
900          * Output a TLS symbol for Mach-O.
901          *
902          * A TLS variable in the Mach-O format consists of two symbols.
903          * One symbol for the data, which contains the initializer, if any.
904          * The name of this symbol is the same as the variable, but with the
905          * "$tlv$init" suffix. If the variable has an initializer it's placed in
906          * the __thread_data section. Otherwise it's placed in the __thread_bss
907          * section.
908          *
909          * The other symbol is for the TLV descriptor. The symbol has the same
910          * name as the variable and is placed in the __thread_vars section.
911          * A TLV descriptor has the following structure, where T is the type of
912          * the variable:
913          *
914          * struct TLVDescriptor(T)
915          * {
916          *     extern(C) T* function(TLVDescriptor*) thunk;
917          *     size_t key;
918          *     size_t offset;
919          * }
920          *
921          * Params:
922          *      vd = the variable declaration for the symbol
923          *      s = the backend Symbol corresponsing to vd
924          *      sz = data size of s
925          *      dtb = where to put the data
926          */
927         static void tlsToDt(VarDeclaration vd, Symbol *s, uint sz, ref DtBuilder dtb, bool isCfile)
928         {
929             assert(config.objfmt == OBJ_MACH && target.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread);
930 
931             Symbol *tlvInit = createTLVDataSymbol(vd, s);
932             auto tlvInitDtb = DtBuilder(0);
933 
934             if (sz == 0)
935                 tlvInitDtb.nzeros(1);
936             else if (vd._init)
937                 initializerToDt(vd, tlvInitDtb, isCfile);
938             else
939                 Type_toDt(vd.type, tlvInitDtb);
940 
941             tlvInit.Sdt = tlvInitDtb.finish();
942             outdata(tlvInit);
943 
944             if (target.is64bit)
945                 tlvInit.Sclass = SC.extern_;
946 
947             Symbol* tlvBootstrap = objmod.tlv_bootstrap();
948             dtb.xoff(tlvBootstrap, 0, TYnptr);
949             dtb.size(0);
950             dtb.xoff(tlvInit, 0, TYnptr);
951         }
952 
953         /**
954          * Creates the data symbol used to initialize a TLS variable for Mach-O.
955          *
956          * Params:
957          *      vd = the variable declaration for the symbol
958          *      s = the back end symbol corresponding to vd
959          *
960          * Returns: the newly created symbol
961          */
962         static Symbol *createTLVDataSymbol(VarDeclaration vd, Symbol *s)
963         {
964             assert(config.objfmt == OBJ_MACH && target.is64bit && (s.Stype.Tty & mTYLINK) == mTYthread);
965 
966             // Compute identifier for tlv symbol
967             OutBuffer buffer;
968             buffer.writestring(s.Sident.ptr);
969             buffer.writestring("$tlv$init");
970             const(char)[] tlvInitName = buffer[];
971 
972             // Compute type for tlv symbol
973             type *t = type_fake(vd.type.ty);
974             type_setty(&t, t.Tty | mTYthreadData);
975             type_setmangle(&t, mangle(vd));
976 
977             Symbol *tlvInit = symbol_name(tlvInitName, SC.static_, t);
978             tlvInit.Sdt = null;
979             tlvInit.Salignment = type_alignsize(s.Stype);
980             if (vd._linkage == LINK.cpp)
981                 tlvInit.Sflags |= SFLpublic;
982 
983             return tlvInit;
984         }
985 
986         /**
987          * Returns the target mangling mangle_t for the given variable.
988          *
989          * Params:
990          *      vd = the variable declaration
991          *
992          * Returns:
993          *      the mangling that should be used for variable
994          */
995         static mangle_t mangle(const VarDeclaration vd)
996         {
997             final switch (vd.resolvedLinkage())
998             {
999                 case LINK.windows:
1000                     return target.is64bit ? mTYman_c : mTYman_std;
1001 
1002                 case LINK.objc:
1003                 case LINK.c:
1004                     return mTYman_c;
1005 
1006                 case LINK.d:
1007                     return mTYman_d;
1008 
1009                 case LINK.cpp:
1010                     return mTYman_cpp;
1011 
1012                 case LINK.default_:
1013                 case LINK.system:
1014                     printf("linkage = %d\n", vd._linkage);
1015                     assert(0);
1016             }
1017         }
1018     }
1019 
1020     scope v = new ToObjFile(multiobj);
1021     ds.accept(v);
1022 }
1023 
1024 
1025 /*********************************
1026  * Finish semantic analysis of functions in vtbl[].
1027  * Params:
1028  *    cd = class which has the vtbl[]
1029  * Returns:
1030  *    true for success (no errors)
1031  */
1032 private bool finishVtbl(ClassDeclaration cd)
1033 {
1034     bool hasError = false;
1035 
1036     foreach (i; cd.vtblOffset() .. cd.vtbl.length)
1037     {
1038         FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
1039 
1040         //printf("\tvtbl[%d] = %p\n", i, fd);
1041         if (!fd || !fd.fbody && cd.isAbstract())
1042         {
1043             // Nothing to do
1044             continue;
1045         }
1046         // Ensure function has a return value
1047         // https://issues.dlang.org/show_bug.cgi?id=4869
1048         if (!fd.functionSemantic())
1049         {
1050             hasError = true;
1051         }
1052 
1053         if (!cd.isFuncHidden(fd) || fd.isFuture())
1054         {
1055             // All good, no name hiding to check for
1056             continue;
1057         }
1058 
1059         /* fd is hidden from the view of this class.
1060          * If fd overlaps with any function in the vtbl[], then
1061          * issue 'hidden' error.
1062          */
1063         foreach (j; 1 .. cd.vtbl.length)
1064         {
1065             if (j == i)
1066                 continue;
1067             FuncDeclaration fd2 = cd.vtbl[j].isFuncDeclaration();
1068             if (!fd2.ident.equals(fd.ident))
1069                 continue;
1070             if (fd2.isFuture())
1071                 continue;
1072             if (!fd.leastAsSpecialized(fd2, null) && !fd2.leastAsSpecialized(fd, null))
1073                 continue;
1074             // Hiding detected: same name, overlapping specializations
1075             TypeFunction tf = fd.type.toTypeFunction();
1076             cd.error("use of `%s%s` is hidden by `%s`; use `alias %s = %s.%s;` to introduce base class overload set",
1077                 fd.toPrettyChars(),
1078                 parametersTypeToChars(tf.parameterList),
1079                 cd.toChars(),
1080                 fd.toChars(),
1081                 fd.parent.toChars(),
1082                 fd.toChars());
1083             hasError = true;
1084             break;
1085         }
1086     }
1087 
1088     return !hasError;
1089 }
1090 
1091 
1092 /******************************************
1093  * Get offset of base class's vtbl[] initializer from start of csym.
1094  * Returns ~0 if not this csym.
1095  */
1096 
1097 uint baseVtblOffset(ClassDeclaration cd, BaseClass *bc)
1098 {
1099     //printf("ClassDeclaration.baseVtblOffset('%s', bc = %p)\n", cd.toChars(), bc);
1100     uint csymoffset = target.classinfosize;    // must be ClassInfo.size
1101     csymoffset += cd.vtblInterfaces.length * (4 * target.ptrsize);
1102 
1103     for (size_t i = 0; i < cd.vtblInterfaces.length; i++)
1104     {
1105         BaseClass *b = (*cd.vtblInterfaces)[i];
1106 
1107         if (b == bc)
1108             return csymoffset;
1109         csymoffset += b.sym.vtbl.length * target.ptrsize;
1110     }
1111 
1112     // Put out the overriding interface vtbl[]s.
1113     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1114     //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
1115     ClassDeclaration cd2;
1116 
1117     for (cd2 = cd.baseClass; cd2; cd2 = cd2.baseClass)
1118     {
1119         foreach (k; 0 .. cd2.vtblInterfaces.length)
1120         {
1121             BaseClass *bs = (*cd2.vtblInterfaces)[k];
1122             if (bs.fillVtbl(cd, null, 0))
1123             {
1124                 if (bc == bs)
1125                 {
1126                     //printf("\tcsymoffset = x%x\n", csymoffset);
1127                     return csymoffset;
1128                 }
1129                 csymoffset += bs.sym.vtbl.length * target.ptrsize;
1130             }
1131         }
1132     }
1133 
1134     return ~0;
1135 }
1136 
1137 /*******************
1138  * Emit the vtbl[] to static data
1139  * Params:
1140  *    dtb = static data builder
1141  *    b = base class
1142  *    bvtbl = array of functions to put in this vtbl[]
1143  *    pc = classid for this vtbl[]
1144  *    k = offset from pc to classinfo
1145  * Returns:
1146  *    number of bytes emitted
1147  */
1148 private size_t emitVtbl(ref DtBuilder dtb, BaseClass *b, ref FuncDeclarations bvtbl, ClassDeclaration pc, size_t k)
1149 {
1150     //printf("\toverriding vtbl[] for %s\n", b.sym.toChars());
1151     ClassDeclaration id = b.sym;
1152 
1153     const id_vtbl_dim = id.vtbl.length;
1154     assert(id_vtbl_dim <= bvtbl.length);
1155 
1156     size_t jstart = 0;
1157     if (id.vtblOffset())
1158     {
1159         // First entry is struct Interface reference
1160         dtb.xoff(toSymbol(pc), cast(uint)(target.classinfosize + k * (4 * target.ptrsize)), TYnptr);
1161         jstart = 1;
1162     }
1163 
1164     foreach (j; jstart .. id_vtbl_dim)
1165     {
1166         FuncDeclaration fd = bvtbl[j];
1167         if (fd)
1168         {
1169             auto offset2 = b.offset;
1170             if (fd.interfaceVirtual)
1171             {
1172                 offset2 -= fd.interfaceVirtual.offset;
1173             }
1174             dtb.xoff(toThunkSymbol(fd, offset2), 0, TYnptr);
1175         }
1176         else
1177             dtb.size(0);
1178     }
1179     return id_vtbl_dim * target.ptrsize;
1180 }
1181 
1182 
1183 /******************************************************
1184  * Generate the ClassInfo for a Class (__classZ) symbol.
1185  * Write it to the object file.
1186  * Similar to genClassInfoForInterface().
1187  * Params:
1188  *      cd = the class
1189  *      sinit = the Initializer (__initZ) symbol for the class
1190  */
1191 private void genClassInfoForClass(ClassDeclaration cd, Symbol* sinit)
1192 {
1193     // Put out the ClassInfo, which will be the __ClassZ symbol in the object file
1194     SC scclass = SC.comdat;
1195     cd.csym.Sclass = scclass;
1196     cd.csym.Sfl = FLdata;
1197 
1198     /* The layout is:
1199        {
1200             void **vptr;
1201             monitor_t monitor;
1202             byte[] m_init;              // static initialization data
1203             string name;                // class name
1204             void*[] vtbl;
1205             Interface[] interfaces;
1206             ClassInfo base;             // base class
1207             void* destructor;
1208             void function(Object) classInvariant;   // class invariant
1209             ClassFlags m_flags;
1210             void* deallocator;
1211             OffsetTypeInfo[] offTi;
1212             void function(Object) defaultConstructor;
1213             //const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
1214             immutable(void)* m_RTInfo;
1215             //TypeInfo typeinfo;
1216        }
1217      */
1218     uint offset = target.classinfosize;    // must be ClassInfo.size
1219     if (Type.typeinfoclass)
1220     {
1221         if (Type.typeinfoclass.structsize != target.classinfosize)
1222         {
1223             debug printf("target.classinfosize = x%x, Type.typeinfoclass.structsize = x%x\n", offset, Type.typeinfoclass.structsize);
1224             cd.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1225             fatal();
1226         }
1227     }
1228 
1229     auto dtb = DtBuilder(0);
1230 
1231     if (auto tic = Type.typeinfoclass)
1232     {
1233         dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for TypeInfo_Class : ClassInfo
1234         if (tic.hasMonitor())
1235             dtb.size(0);                        // monitor
1236     }
1237     else
1238     {
1239         dtb.size(0);                    // BUG: should be an assert()
1240         dtb.size(0);                    // call hasMonitor()?
1241     }
1242 
1243     // m_init[]
1244     assert(cd.structsize >= 8 || (cd.classKind == ClassKind.cpp && cd.structsize >= 4));
1245     dtb.size(cd.structsize);           // size
1246     dtb.xoff(sinit, 0, TYnptr);         // initializer
1247 
1248     // name[]
1249     const(char) *name = cd.ident.toChars();
1250     size_t namelen = strlen(name);
1251     if (!(namelen > 9 && memcmp(name, "TypeInfo_".ptr, 9) == 0))
1252     {
1253         name = cd.toPrettyChars(/*QualifyTypes=*/ true);
1254         namelen = strlen(name);
1255     }
1256     dtb.size(namelen);
1257     dt_t *pdtname = dtb.xoffpatch(cd.csym, 0, TYnptr);
1258 
1259     // vtbl[]
1260     dtb.size(cd.vtbl.length);
1261     if (cd.vtbl.length)
1262         dtb.xoff(cd.vtblsym.csym, 0, TYnptr);
1263     else
1264         dtb.size(0);
1265 
1266     // interfaces[]
1267     dtb.size(cd.vtblInterfaces.length);
1268     if (cd.vtblInterfaces.length)
1269         dtb.xoff(cd.csym, offset, TYnptr);      // (*)
1270     else
1271         dtb.size(0);
1272 
1273     // base
1274     if (cd.baseClass)
1275         dtb.xoff(toSymbol(cd.baseClass), 0, TYnptr);
1276     else
1277         dtb.size(0);
1278 
1279     // destructor
1280     if (cd.tidtor)
1281         dtb.xoff(toSymbol(cd.tidtor), 0, TYnptr);
1282     else
1283         dtb.size(0);
1284 
1285     // classInvariant
1286     if (cd.inv)
1287         dtb.xoff(toSymbol(cd.inv), 0, TYnptr);
1288     else
1289         dtb.size(0);
1290 
1291     // flags
1292     ClassFlags flags = ClassFlags.hasOffTi;
1293     if (cd.isCOMclass()) flags |= ClassFlags.isCOMclass;
1294     if (cd.isCPPclass()) flags |= ClassFlags.isCPPclass;
1295     flags |= ClassFlags.hasGetMembers;
1296     flags |= ClassFlags.hasTypeInfo;
1297     if (cd.ctor)
1298         flags |= ClassFlags.hasCtor;
1299     for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1300     {
1301         if (pc.dtor)
1302         {
1303             flags |= ClassFlags.hasDtor;
1304             break;
1305         }
1306     }
1307     if (cd.isAbstract())
1308         flags |= ClassFlags.isAbstract;
1309 
1310     flags |= ClassFlags.noPointers;     // initially assume no pointers
1311 Louter:
1312     for (ClassDeclaration pc = cd; pc; pc = pc.baseClass)
1313     {
1314         if (pc.members)
1315         {
1316             for (size_t i = 0; i < pc.members.length; i++)
1317             {
1318                 Dsymbol sm = (*pc.members)[i];
1319                 //printf("sm = %s %s\n", sm.kind(), sm.toChars());
1320                 if (sm.hasPointers())
1321                 {
1322                     flags &= ~ClassFlags.noPointers;  // not no-how, not no-way
1323                     break Louter;
1324                 }
1325             }
1326         }
1327     }
1328     dtb.size(flags);
1329 
1330     // deallocator
1331     dtb.size(0);
1332 
1333     // offTi[]
1334     dtb.size(0);
1335     dtb.size(0);            // null for now, fix later
1336 
1337     // defaultConstructor
1338     if (cd.defaultCtor && !(cd.defaultCtor.storage_class & STC.disable))
1339         dtb.xoff(toSymbol(cd.defaultCtor), 0, TYnptr);
1340     else
1341         dtb.size(0);
1342 
1343     // m_RTInfo
1344     if (cd.getRTInfo)
1345         Expression_toDt(cd.getRTInfo, dtb);
1346     else if (flags & ClassFlags.noPointers)
1347         dtb.size(0);
1348     else
1349         dtb.size(1);
1350 
1351     //dtb.xoff(toSymbol(cd.type.vtinfo), 0, TYnptr); // typeinfo
1352 
1353     //////////////////////////////////////////////
1354 
1355     // Put out (*vtblInterfaces)[]. Must immediately follow csym, because
1356     // of the fixup (*)
1357 
1358     offset += cd.vtblInterfaces.length * (4 * target.ptrsize);
1359     for (size_t i = 0; i < cd.vtblInterfaces.length; i++)
1360     {
1361         BaseClass *b = (*cd.vtblInterfaces)[i];
1362         ClassDeclaration id = b.sym;
1363 
1364         /* The layout is:
1365          *  struct Interface
1366          *  {
1367          *      ClassInfo classinfo;
1368          *      void*[] vtbl;
1369          *      size_t offset;
1370          *  }
1371          */
1372 
1373         // Fill in vtbl[]
1374         b.fillVtbl(cd, &b.vtbl, 1);
1375 
1376         // classinfo
1377         dtb.xoff(toSymbol(id), 0, TYnptr);
1378 
1379         // vtbl[]
1380         dtb.size(id.vtbl.length);
1381         dtb.xoff(cd.csym, offset, TYnptr);
1382 
1383         // offset
1384         dtb.size(b.offset);
1385     }
1386 
1387     // Put out the (*vtblInterfaces)[].vtbl[]
1388     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1389     //printf("putting out %d interface vtbl[]s for '%s'\n", vtblInterfaces.length, toChars());
1390     foreach (i; 0 .. cd.vtblInterfaces.length)
1391     {
1392         BaseClass *b = (*cd.vtblInterfaces)[i];
1393         offset += emitVtbl(dtb, b, b.vtbl, cd, i);
1394     }
1395 
1396     // Put out the overriding interface vtbl[]s.
1397     // This must be mirrored with ClassDeclaration.baseVtblOffset()
1398     //printf("putting out overriding interface vtbl[]s for '%s' at offset x%x\n", toChars(), offset);
1399     for (ClassDeclaration pc = cd.baseClass; pc; pc = pc.baseClass)
1400     {
1401         foreach (i; 0 .. pc.vtblInterfaces.length)
1402         {
1403             BaseClass *b = (*pc.vtblInterfaces)[i];
1404             FuncDeclarations bvtbl;
1405             if (b.fillVtbl(cd, &bvtbl, 0))
1406             {
1407                 offset += emitVtbl(dtb, b, bvtbl, pc, i);
1408             }
1409         }
1410     }
1411 
1412     //////////////////////////////////////////////
1413 
1414     dtpatchoffset(pdtname, offset);
1415 
1416     dtb.nbytes(cast(uint)(namelen + 1), name);
1417     const size_t namepad = -(namelen + 1) & (target.ptrsize - 1); // align
1418     dtb.nzeros(cast(uint)namepad);
1419 
1420     cd.csym.Sdt = dtb.finish();
1421     // ClassInfo cannot be const data, because we use the monitor on it
1422     outdata(cd.csym);
1423     if (cd.isExport())
1424         objmod.export_symbol(cd.csym, 0);
1425 }
1426 
1427 /******************************************************
1428  * Generate the ClassInfo for an Interface (classZ symbol).
1429  * Write it to the object file.
1430  * Params:
1431  *      id = the interface
1432  */
1433 private void genClassInfoForInterface(InterfaceDeclaration id)
1434 {
1435     SC scclass = SC.comdat;
1436 
1437     // Put out the ClassInfo
1438     id.csym.Sclass = scclass;
1439     id.csym.Sfl = FLdata;
1440 
1441     /* The layout is:
1442        {
1443             void **vptr;
1444             monitor_t monitor;
1445             byte[] m_init;              // static initialization data
1446             string name;                // class name
1447             void*[] vtbl;
1448             Interface[] interfaces;
1449             ClassInfo base;             // base class
1450             void* destructor;
1451             void function(Object) classInvariant;   // class invariant
1452             ClassFlags m_flags;
1453             void* deallocator;
1454             OffsetTypeInfo[] offTi;
1455             void function(Object) defaultConstructor;
1456             //const(MemberInfo[]) function(string) xgetMembers;   // module getMembers() function
1457             immutable(void)* m_RTInfo;
1458             //TypeInfo typeinfo;
1459        }
1460      */
1461     auto dtb = DtBuilder(0);
1462 
1463     if (auto tic = Type.typeinfoclass)
1464     {
1465         dtb.xoff(toVtblSymbol(tic), 0, TYnptr); // vtbl for ClassInfo
1466         if (tic.hasMonitor())
1467             dtb.size(0);                        // monitor
1468     }
1469     else
1470     {
1471         dtb.size(0);                    // BUG: should be an assert()
1472         dtb.size(0);                    // call hasMonitor()?
1473     }
1474 
1475     // m_init[]
1476     dtb.size(0);                        // size
1477     dtb.size(0);                        // initializer
1478 
1479     // name[]
1480     const(char) *name = id.toPrettyChars(/*QualifyTypes=*/ true);
1481     size_t namelen = strlen(name);
1482     dtb.size(namelen);
1483     dt_t *pdtname = dtb.xoffpatch(id.csym, 0, TYnptr);
1484 
1485     // vtbl[]
1486     dtb.size(0);
1487     dtb.size(0);
1488 
1489     // interfaces[]
1490     uint offset = target.classinfosize;
1491     dtb.size(id.vtblInterfaces.length);
1492     if (id.vtblInterfaces.length)
1493     {
1494         if (Type.typeinfoclass)
1495         {
1496             if (Type.typeinfoclass.structsize != offset)
1497             {
1498                 id.error("mismatch between dmd and object.d or object.di found. Check installation and import paths with -v compiler switch.");
1499                 fatal();
1500             }
1501         }
1502         dtb.xoff(id.csym, offset, TYnptr);      // (*)
1503     }
1504     else
1505     {
1506         dtb.size(0);
1507     }
1508 
1509     // base
1510     assert(!id.baseClass);
1511     dtb.size(0);
1512 
1513     // destructor
1514     dtb.size(0);
1515 
1516     // classInvariant
1517     dtb.size(0);
1518 
1519     // flags
1520     ClassFlags flags = ClassFlags.hasOffTi | ClassFlags.hasTypeInfo;
1521     if (id.isCOMinterface()) flags |= ClassFlags.isCOMclass;
1522     dtb.size(flags);
1523 
1524     // deallocator
1525     dtb.size(0);
1526 
1527     // offTi[]
1528     dtb.size(0);
1529     dtb.size(0);            // null for now, fix later
1530 
1531     // defaultConstructor
1532     dtb.size(0);
1533 
1534     // xgetMembers
1535     //dtb.size(0);
1536 
1537     // m_RTInfo
1538     if (id.getRTInfo)
1539         Expression_toDt(id.getRTInfo, dtb);
1540     else
1541         dtb.size(0);       // no pointers
1542 
1543     //dtb.xoff(toSymbol(id.type.vtinfo), 0, TYnptr); // typeinfo
1544 
1545     //////////////////////////////////////////////
1546 
1547     // Put out (*vtblInterfaces)[]. Must immediately follow csym, because
1548     // of the fixup (*)
1549 
1550     offset += id.vtblInterfaces.length * (4 * target.ptrsize);
1551     for (size_t i = 0; i < id.vtblInterfaces.length; i++)
1552     {
1553         BaseClass *b = (*id.vtblInterfaces)[i];
1554         ClassDeclaration base = b.sym;
1555 
1556         // classinfo
1557         dtb.xoff(toSymbol(base), 0, TYnptr);
1558 
1559         // vtbl[]
1560         dtb.size(0);
1561         dtb.size(0);
1562 
1563         // offset
1564         dtb.size(b.offset);
1565     }
1566 
1567     //////////////////////////////////////////////
1568 
1569     dtpatchoffset(pdtname, offset);
1570 
1571     dtb.nbytes(cast(uint)(namelen + 1), name);
1572     const size_t namepad =  -(namelen + 1) & (target.ptrsize - 1); // align
1573     dtb.nzeros(cast(uint)namepad);
1574 
1575     id.csym.Sdt = dtb.finish();
1576     out_readonly(id.csym);
1577     outdata(id.csym);
1578     if (id.isExport())
1579         objmod.export_symbol(id.csym, 0);
1580 }