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