1 /**
2  * Convert a D symbol to a symbol the linker understands (with mangled name).
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, _tocsym.d)
8  * Documentation:  https://dlang.org/phobos/dmd_tocsym.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/tocsym.d
10  */
11 
12 module dmd.tocsym;
13 
14 import core.stdc.stdio;
15 import core.stdc.string;
16 
17 import dmd.root.array;
18 import dmd.root.complex;
19 import dmd.root.rmem;
20 
21 import dmd.aggregate;
22 import dmd.arraytypes;
23 import dmd.astenums;
24 import dmd.ctfeexpr;
25 import dmd.declaration;
26 import dmd.dclass;
27 import dmd.denum;
28 import dmd.dmdparams;
29 import dmd.dmodule;
30 import dmd.dstruct;
31 import dmd.dsymbol;
32 import dmd.dtemplate;
33 import dmd.e2ir;
34 import dmd.errors;
35 import dmd.expression;
36 import dmd.func;
37 import dmd.globals;
38 import dmd.glue;
39 import dmd.identifier;
40 import dmd.id;
41 import dmd.init;
42 import dmd.location;
43 import dmd.mtype;
44 import dmd.target;
45 import dmd.toctype;
46 import dmd.todt;
47 import dmd.toir;
48 import dmd.tokens;
49 import dmd.visitor;
50 import dmd.dmangle;
51 
52 import dmd.backend.cdef;
53 import dmd.backend.cc;
54 import dmd.backend.dt;
55 import dmd.backend.type;
56 import dmd.backend.global;
57 import dmd.backend.oper;
58 import dmd.backend.cgcv;
59 import dmd.backend.symtab;
60 import dmd.backend.ty;
61 
62 extern (C++):
63 
64 
65 /*************************************
66  * Helper
67  */
68 
69 Symbol *toSymbolX(Dsymbol ds, const(char)* prefix, SC sclass, type *t, const(char)* suffix)
70 {
71     //printf("Dsymbol::toSymbolX('%s')\n", prefix);
72     import dmd.common.string : SmallBuffer;
73     import dmd.common.outbuffer : OutBuffer;
74 
75     OutBuffer buf;
76     mangleToBuffer(ds, buf);
77     size_t nlen = buf.length;
78     const(char)* n = buf.peekChars();
79     assert(n);
80 
81     import core.stdc.string : strlen;
82     size_t prefixlen = strlen(prefix);
83     size_t suffixlen = strlen(suffix);
84     size_t idlen = 2 + nlen + size_t.sizeof * 3 + prefixlen + suffixlen + 1;
85 
86     char[64] idbuf = void;
87     auto sb = SmallBuffer!(char)(idlen, idbuf[]);
88     char *id = sb.ptr;
89 
90     int nwritten = snprintf(id, idlen, "_D%.*s%d%.*s%.*s",
91         cast(int)nlen, n,
92         cast(int)prefixlen, cast(int)prefixlen, prefix,
93         cast(int)suffixlen, suffix);
94     assert(cast(uint)nwritten < idlen);         // nwritten does not include the terminating 0 char
95 
96     Symbol *s = symbol_name(id[0 .. nwritten], sclass, t);
97 
98     //printf("-Dsymbol::toSymbolX() %s\n", id);
99     return s;
100 }
101 
102 /*************************************
103  */
104 
105 Symbol *toSymbol(Dsymbol s)
106 {
107     //printf("toSymbol() %s\n", s.toChars());
108 
109     extern (C++) static final class ToSymbol : Visitor
110     {
111         alias visit = Visitor.visit;
112 
113         Symbol *result;
114 
115         this() scope @safe
116         {
117             result = null;
118         }
119 
120         override void visit(Dsymbol s)
121         {
122             printf("Dsymbol.toSymbol() '%s', kind = '%s'\n", s.toChars(), s.kind());
123             assert(0);          // BUG: implement
124         }
125 
126         override void visit(SymbolDeclaration sd)
127         {
128             result = toInitializer(sd.dsym);
129         }
130 
131         override void visit(VarDeclaration vd)
132         {
133             //printf("VarDeclaration.toSymbol(%s)\n", vd.toChars());
134             if (vd.needThis())
135                 fprintf(stderr, "VarDeclaration.toSymbol(%s) needThis kind: %s\n", vd.toPrettyChars(), vd.kind());
136             assert(!vd.needThis());
137 
138             import dmd.common.outbuffer : OutBuffer;
139             OutBuffer buf;
140             bool isNRVO = false;
141             const(char)[] id = vd.ident.toString();
142             if (vd.isDataseg())
143             {
144                 mangleToBuffer(vd, buf);
145                 id = buf[];
146             }
147             else
148             {
149                 if (FuncDeclaration fd = vd.toParent2().isFuncDeclaration())
150                 {
151                     if (fd.isNRVO() && fd.nrvo_var == vd)
152                     {
153                         buf.writestring("__nrvo_");
154                         buf.writestring(id);
155                         id = buf[];
156                         isNRVO = true;
157                     }
158                 }
159             }
160             Symbol *s = symbol_calloc(id);
161             s.Salignment = vd.alignment.isDefault() ? -1 : vd.alignment.get();
162             if (vd.storage_class & STC.temp)
163                 s.Sflags |= SFLartifical;
164             if (isNRVO)
165                 s.Sflags |= SFLnodebug;
166             if (vd.adFlags & Declaration.nounderscore)
167                 s.Sflags |= SFLnounderscore;
168 
169             TYPE *t;
170             if (vd.storage_class & (STC.out_ | STC.ref_))
171             {
172                 t = type_allocn(TYnref, Type_toCtype(vd.type));
173                 t.Tcount++;
174             }
175             else if (vd.storage_class & STC.lazy_)
176             {
177                 if (target.os == Target.OS.Windows && target.isX86_64 && vd.isParameter())
178                     t = type_fake(TYnptr);
179                 else
180                     t = type_fake(TYdelegate);          // Tdelegate as C type
181                 t.Tcount++;
182             }
183             else if (vd.isParameter() && ISX64REF(vd))
184             {
185                 t = type_allocn(TYnref, Type_toCtype(vd.type));
186                 t.Tcount++;
187             }
188             else
189             {
190                 t = Type_toCtype(vd.type);
191                 t.Tcount++;
192             }
193 
194             /* Even if a symbol is immutable, if it has a constructor then
195              * the constructor mutates it. Remember that constructors can
196              * be inlined into other code.
197              * Just can't rely on it being immutable.
198              */
199             if (t.Tty & (mTYimmutable | mTYconst))
200             {
201                 if (vd.ctorinit)
202                 {
203                     /* It was initialized in a constructor, so not really immutable
204                      * as far as the optimizer is concerned, as in this case:
205                      *   immutable int x;
206                      *   shared static this() { x += 3; }
207                      */
208                     t = type_setty(&t, t.Tty & ~(mTYimmutable | mTYconst));
209                 }
210                 else if (auto ts = vd.type.isTypeStruct())
211                 {
212                     if (!ts.isMutable() && ts.sym.ctor)
213                     {
214                         t = type_setty(&t, t.Tty & ~(mTYimmutable | mTYconst));
215                     }
216                 }
217                 else if (auto tc = vd.type.isTypeClass())
218                 {
219                     if (!tc.isMutable() && tc.sym.ctor)
220                     {
221                         t = type_setty(&t, t.Tty & ~(mTYimmutable | mTYconst));
222                     }
223                 }
224             }
225 
226             if (vd.isDataseg())
227             {
228                 if (vd.isThreadlocal() && !(vd.storage_class & STC.temp))
229                 {
230                     /* Thread local storage
231                      */
232                     auto ts = t;
233                     ts.Tcount++;   // make sure a different t is allocated
234                     type_setty(&t, t.Tty | mTYthread);
235                     ts.Tcount--;
236 
237                     if (config.objfmt == OBJ_MACH && _tysize[TYnptr] == 8)
238                         s.Salignment = 2;
239 
240                     if (global.params.v.tls)
241                     {
242                         message(vd.loc, "`%s` is thread local", vd.toChars());
243                     }
244                 }
245                 s.Sclass = SC.extern_;
246                 s.Sfl = FLextern;
247 
248                 /* Make C static variables SCstatic
249                  */
250                 if (vd.storage_class & STC.static_ && vd.isCsymbol())
251                 {
252                     s.Sclass = SC.static_;
253                     s.Sfl = FLdata;
254                 }
255 
256                 /* if it's global or static, then it needs to have a qualified but unmangled name.
257                  * This gives some explanation of the separation in treating name mangling.
258                  * It applies to PDB format, but should apply to CV as PDB derives from CV.
259                  *    https://msdn.microsoft.com/en-us/library/ff553493%28VS.85%29.aspx
260                  */
261                 s.prettyIdent = vd.toPrettyChars(true);
262             }
263             else
264             {
265                 s.Sclass = SC.auto_;
266                 s.Sfl = FLauto;
267 
268                 if (vd.nestedrefs.length)
269                 {
270                     /* Symbol is accessed by a nested function. Make sure
271                      * it is not put in a register, and that the optimizer
272                      * assumes it is modified across function calls and pointer
273                      * dereferences.
274                      */
275                     //printf("\tnested ref, not register\n");
276                     type_setcv(&t, t.Tty | mTYvolatile);
277                 }
278             }
279 
280             if (vd.storage_class & STC.volatile_)
281             {
282                 type_setcv(&t, t.Tty | mTYvolatile);
283             }
284 
285             mangle_t m = 0;
286             final switch (vd.resolvedLinkage())
287             {
288                 case LINK.windows:
289                     m = target.isX86_64 ? mTYman_c : mTYman_std;
290                     break;
291 
292                 case LINK.objc:
293                 case LINK.c:
294                     m = mTYman_c;
295                     break;
296 
297                 case LINK.d:
298                     m = mTYman_d;
299                     break;
300 
301                 case LINK.cpp:
302                     s.Sflags |= SFLpublic;
303                     m = mTYman_cpp;
304                     break;
305 
306                 case LINK.default_:
307                 case LINK.system:
308                     printf("linkage = %d, vd = %s %s @ [%s]\n",
309                         vd._linkage, vd.kind(), vd.toChars(), vd.loc.toChars());
310                     assert(0);
311             }
312 
313             type_setmangle(&t, m);
314             s.Stype = t;
315 
316             s.lposscopestart = toSrcpos(vd.loc);
317             s.lnoscopeend = vd.endlinnum;
318             result = s;
319         }
320 
321         override void visit(TypeInfoDeclaration tid)
322         {
323             //printf("TypeInfoDeclaration.toSymbol(%s), linkage = %d\n", tid.toChars(), tid.linkage);
324             assert(tid.tinfo.ty != Terror);
325             visit(tid.isVarDeclaration());
326         }
327 
328         override void visit(TypeInfoClassDeclaration ticd)
329         {
330             //printf("TypeInfoClassDeclaration.toSymbol(%s), linkage = %d\n", ticd.toChars(), ticd.linkage);
331             ticd.tinfo.isTypeClass().sym.accept(this);
332         }
333 
334         override void visit(FuncAliasDeclaration fad)
335         {
336             fad.funcalias.accept(this);
337         }
338 
339         override void visit(FuncDeclaration fd)
340         {
341             const(char)* id = mangleExact(fd);
342 
343             //printf("FuncDeclaration.toSymbol(%s %s)\n", fd.kind(), fd.toChars());
344 
345             /* MS-LINK cannot handle multiple COMDATs with the same name.
346              * This can happen with two .c files that define the same function.
347              * They get compiled into one .obj file with the `oneobj` setting.
348              * https://issues.dlang.org/show_bug.cgi?id=24129
349              */
350             if (driverParams.oneobj)
351             {
352                 auto mod = fd.getModule();
353                 if (mod &&
354                     mod.isRoot() &&               // included on command line
355                     mod.filetype == FileType.c && // a C file
356                     fd.fbody &&                   // a function definition
357                     fd._linkage == LINK.c &&
358                     !fd.skipCodegen)              // code gen is desired
359                 {
360                     __gshared DsymbolTable Csymtab;  // sorry about another global variable
361                     if (Csymtab is null)
362                         Csymtab = new DsymbolTable();
363 
364                     if (!Csymtab.insert(fd))    // if code was already generated for same-named function
365                     {
366                         /* Use the C symbol for the previously generated function
367                          */
368                         fd.csym = Csymtab.lookup(fd.ident).csym;
369                         result = fd.csym;
370 
371                         fd.skipCodegen = true;
372                         return;
373                     }
374                 }
375             }
376 
377             //printf("\tid = '%s'\n", id);
378             //printf("\ttype = %s\n", fd.type.toChars());
379             auto s = symbol_calloc(id[0 .. strlen(id)]);
380 
381             s.prettyIdent = fd.toPrettyChars(true);
382 
383             /* Make C static functions SCstatic
384              */
385             s.Sclass = (fd.storage_class & STC.static_ && fd.isCsymbol())
386                 ? SC.static_
387                 : SC.global;
388 
389             symbol_func(s);
390             func_t *f = s.Sfunc;
391             if (fd.isVirtual() && fd.vtblIndex != -1)
392                 f.Fflags |= Fvirtual;
393             else if (fd.isMember2() && fd.isStatic())
394                 f.Fflags |= Fstatic;
395 
396             if (fd.isSafe())
397                 f.Fflags3 |= F3safe;
398 
399             if (fd.inlining == PINLINE.default_ && global.params.useInline ||
400                 fd.inlining == PINLINE.always)
401             {
402                 // this is copied from inline.d
403                 if (!fd.fbody ||
404                     fd.ident == Id.ensure ||
405                     fd.skipCodegen ||
406                     (fd.ident == Id.require &&
407                      fd.toParent().isFuncDeclaration() &&
408                      fd.toParent().isFuncDeclaration().needThis()) ||
409                                 (fd.isSynchronized() ||
410                                  fd.isImportedSymbol() ||
411                                  fd.hasNestedFrameRefs() ||
412                                  (fd.isVirtual() && !fd.isFinalFunc())))
413                 { }
414                 else
415                     f.Fflags |= Finline;    // inline this function if possible
416             }
417 
418             if (fd.type.toBasetype().isTypeFunction().nextOf().isTypeNoreturn() || fd.noreturn)
419                 s.Sflags |= SFLexit;    // the function never returns
420 
421             f.Fstartline = toSrcpos(fd.loc);
422             f.Fendline = fd.endloc.linnum ? toSrcpos(fd.endloc) : f.Fstartline;
423 
424             auto t = Type_toCtype(fd.type);
425             if (fd.isNaked)
426                 type_setty(&t, t.Tty | mTYnaked);
427 
428             const msave = t.Tmangle;
429             if (fd.isMain())
430             {
431                 t.Tty = TYnfunc;
432                 t.Tmangle = mTYman_c;
433                 f.Fflags3 |= Fmain;
434             }
435             else
436             {
437                 final switch (fd.resolvedLinkage())
438                 {
439                     case LINK.windows:
440                         t.Tmangle = target.isX86_64 ? mTYman_c : mTYman_std;
441                         break;
442 
443                     case LINK.c:
444                         if (fd.adFlags & Declaration.nounderscore)
445                             s.Sflags |= SFLnounderscore;
446                         goto case;
447                     case LINK.objc:
448                         t.Tmangle = mTYman_c;
449                         break;
450 
451                     case LINK.d:
452                         t.Tmangle = mTYman_d;
453                         break;
454                     case LINK.cpp:
455                         s.Sflags |= SFLpublic;
456                         /* Nested functions use the same calling convention as
457                          * member functions, because both can be used as delegates. */
458                         if ((fd.isThis() || fd.isNested()) && !target.isX86_64 && target.os == Target.OS.Windows)
459                         {
460                             if ((cast(TypeFunction)fd.type).parameterList.varargs == VarArg.variadic)
461                             {
462                                 t.Tty = TYnfunc;
463                             }
464                             else
465                             {
466                                 t.Tty = TYmfunc;
467                             }
468                         }
469                         t.Tmangle = mTYman_cpp;
470                         break;
471                     case LINK.default_:
472                     case LINK.system:
473                         printf("linkage = %d\n", fd._linkage);
474                         assert(0);
475                 }
476             }
477 
478             if (msave)
479                 assert(msave == t.Tmangle);
480             //printf("Tty = %x, mangle = x%x\n", t.Tty, t.Tmangle);
481             t.Tcount++;
482             s.Stype = t;
483             //s.Sfielddef = this;
484 
485             result = s;
486         }
487 
488         static type* getClassInfoCType()
489         {
490             __gshared Symbol* scc;
491             if (!scc)
492                 scc = fake_classsym(Id.ClassInfo);
493             return scc.Stype;
494         }
495 
496         /*************************************
497          * Create the "ClassInfo" symbol
498          */
499 
500         override void visit(ClassDeclaration cd)
501         {
502             auto s = toSymbolX(cd, "__Class", SC.extern_, getClassInfoCType(), "Z");
503             s.Sfl = FLextern;
504             s.Sflags |= SFLnodebug;
505             result = s;
506         }
507 
508         /*************************************
509          * Create the "InterfaceInfo" symbol
510          */
511 
512         override void visit(InterfaceDeclaration id)
513         {
514             auto s = toSymbolX(id, "__Interface", SC.extern_, getClassInfoCType(), "Z");
515             s.Sfl = FLextern;
516             s.Sflags |= SFLnodebug;
517             result = s;
518         }
519 
520         /*************************************
521          * Create the "ModuleInfo" symbol
522          */
523 
524         override void visit(Module m)
525         {
526             auto s = toSymbolX(m, "__ModuleInfo", SC.extern_, getClassInfoCType(), "Z");
527             s.Sfl = FLextern;
528             s.Sflags |= SFLnodebug;
529             result = s;
530         }
531     }
532 
533     if (s.csym)
534         return s.csym;
535 
536     scope ToSymbol v = new ToSymbol();
537     s.accept(v);
538     s.csym = v.result;
539     return v.result;
540 }
541 
542 
543 /*************************************
544  * Create Windows import symbol from backend Symbol.
545  * Params:
546  *      sym = backend symbol
547  *      loc = location for error message purposes
548  * Returns:
549  *      import symbol
550  */
551 
552 private Symbol *createImport(Symbol *sym, Loc loc)
553 {
554     //printf("Dsymbol.createImport('%s')\n", sym.Sident.ptr);
555     const char* n = sym.Sident.ptr;
556     import core.stdc.stdlib : alloca;
557     const allocLen = 6 + strlen(n) + 1 + type_paramsize(sym.Stype).sizeof*3 + 1;
558     char *id = cast(char *) alloca(allocLen);
559     int idlen;
560     if (target.os & Target.OS.Posix)
561     {
562         error(loc, "could not generate import symbol for this platform");
563         fatal();
564     }
565     else if (sym.Stype.Tmangle == mTYman_std && tyfunc(sym.Stype.Tty))
566     {
567         if (target.os == Target.OS.Windows && target.isX86_64)
568             idlen = snprintf(id, allocLen, "__imp_%s",n);
569         else
570             idlen = snprintf(id, allocLen, "_imp__%s@%u",n,cast(uint)type_paramsize(sym.Stype));
571     }
572     else
573     {
574         idlen = snprintf(id, allocLen, (target.os == Target.OS.Windows && target.isX86_64) ? "__imp_%s" : (sym.Stype.Tmangle == mTYman_cpp) ? "_imp_%s" : "_imp__%s",n);
575     }
576     auto t = type_alloc(TYnptr | mTYconst);
577     t.Tnext = sym.Stype;
578     t.Tnext.Tcount++;
579     t.Tmangle = mTYman_c;
580     t.Tcount++;
581     auto s = symbol_calloc(id[0 .. idlen]);
582     s.Stype = t;
583     s.Sclass = SC.extern_;
584     s.Sfl = FLextern;
585     return s;
586 }
587 
588 /*********************************
589  * Generate import symbol from symbol.
590  */
591 
592 Symbol *toImport(Declaration ds)
593 {
594     if (!ds.isym)
595     {
596         if (!ds.csym)
597             ds.csym = toSymbol(ds);
598         ds.isym = createImport(ds.csym, ds.loc);
599     }
600     return ds.isym;
601 }
602 
603 /*************************************
604  * Thunks adjust the incoming 'this' pointer by 'offset'.
605  */
606 
607 Symbol *toThunkSymbol(FuncDeclaration fd, int offset)
608 {
609     Symbol *s = toSymbol(fd);
610     if (!offset)
611         return s;
612 
613     if (retStyle(fd.type.isTypeFunction(), fd.needThis()) == RET.stack)
614         s.Sfunc.Fflags3 |= F3hiddenPtr;
615 
616     s.Sfunc.Fflags &= ~Finline;  // thunks are not real functions, don't inline them
617 
618     __gshared int tmpnum;
619     const nameLen = 6 + tmpnum.sizeof * 3 + 1;
620     char[nameLen] name = void;
621 
622     const len = snprintf(name.ptr,nameLen,"_THUNK%d",tmpnum++);
623     auto sthunk = symbol_name(name[0 .. len],SC.static_,fd.csym.Stype);
624     sthunk.Sflags |= SFLnodebug | SFLartifical;
625     sthunk.Sflags |= SFLimplem;
626     outthunk(sthunk, fd.csym, 0, TYnptr, -offset, -1, 0);
627     return sthunk;
628 }
629 
630 
631 /**************************************
632  * Fake a struct symbol.
633  */
634 
635 Classsym *fake_classsym(Identifier id)
636 {
637     auto t = type_struct_class(id.toChars(),8,0,
638         null,null,
639         false, false, true, false);
640 
641     t.Ttag.Sstruct.Sflags = STRglobal;
642     t.Tflags |= TFsizeunknown | TFforward;
643     assert(t.Tmangle == 0);
644     t.Tmangle = mTYman_d;
645     return t.Ttag;
646 }
647 
648 /*************************************
649  * This is accessible via the ClassData, but since it is frequently
650  * needed directly (like for rtti comparisons), make it directly accessible.
651  */
652 
653 Symbol *toVtblSymbol(ClassDeclaration cd, bool genCsymbol = true)
654 {
655     if (!cd.vtblsym || !cd.vtblsym.csym)
656     {
657         if (!cd.csym && genCsymbol)
658             toSymbol(cd);
659 
660         auto t = type_allocn(TYnptr | mTYconst, tstypes[TYvoid]);
661         t.Tmangle = mTYman_d;
662         auto s = toSymbolX(cd, "__vtbl", SC.extern_, t, "Z");
663         s.Sflags |= SFLnodebug;
664         s.Sfl = FLextern;
665 
666         auto vtbl = cd.vtblSymbol();
667         vtbl.csym = s;
668     }
669     return cd.vtblsym.csym;
670 }
671 
672 /**********************************
673  * Create the static initializer for the struct/class.
674  */
675 
676 Symbol *toInitializer(AggregateDeclaration ad)
677 {
678     //printf("toInitializer() %s\n", ad.toChars());
679     if (!ad.sinit)
680     {
681         static structalign_t alignOf(Type t)
682         {
683             const explicitAlignment = t.alignment();
684             if (!explicitAlignment.isDefault()) // if overriding default alignment
685                 return explicitAlignment;
686 
687             // Use the default alignment for type t
688             structalign_t sa;
689             sa.set(t.alignsize());
690             return sa;
691         }
692 
693         auto sd = ad.isStructDeclaration();
694         if (sd &&
695             alignOf(sd.type).get() <= 16 &&
696             sd.type.size() <= 128 &&
697             sd.zeroInit &&
698             config.objfmt != OBJ_MACH && // same reason as in toobj.d toObjFile()
699             !(config.objfmt == OBJ_MSCOFF && !target.isX86_64)) // -m32mscoff relocations are wrong
700         {
701             auto bzsave = bzeroSymbol;
702             ad.sinit = getBzeroSymbol();
703 
704             // Ensure emitted only once per object file
705             if (bzsave && bzeroSymbol != bzsave)
706                 assert(0);
707         }
708         else
709         {
710             auto stag = fake_classsym(Id.ClassInfo);
711 
712             Symbol* s;
713 
714             Module m = ad.getModule();
715             if (m.filetype == FileType.c)
716             {
717                 /* For ImportC structs, the module names are stripped from the mangled name.
718                  * This leads to name collisions. Add the module name back in.
719                  */
720                 import dmd.common.outbuffer : OutBuffer;
721                 OutBuffer buf;
722                 buf.writestring("__init");
723                 buf.writestring(m.toChars());
724                 s = toSymbolX(ad, buf.peekChars(), SC.extern_, stag.Stype, "Z");
725             }
726             else
727                 s = toSymbolX(ad, "__init", SC.extern_, stag.Stype, "Z");
728 
729             s.Sfl = FLextern;
730             s.Sflags |= SFLnodebug;
731             if (sd)
732                 s.Salignment = sd.alignment.isDefault() ? -1 : sd.alignment.get();
733             ad.sinit = s;
734         }
735     }
736     return cast(Symbol*)ad.sinit;
737 }
738 
739 Symbol *toInitializer(EnumDeclaration ed)
740 {
741     if (!ed.sinit)
742     {
743         auto stag = fake_classsym(Id.ClassInfo);
744         assert(ed.ident);
745         auto s = toSymbolX(ed, "__init", SC.extern_, stag.Stype, "Z");
746         s.Sfl = FLextern;
747         s.Sflags |= SFLnodebug;
748         ed.sinit = s;
749     }
750     return ed.sinit;
751 }
752 
753 
754 /*****************************************************/
755 /*                   CTFE stuff                      */
756 /*****************************************************/
757 
758 Symbol* toSymbol(StructLiteralExp sle)
759 {
760     //printf("toSymbol() %p.sym: %p\n", sle, sle.sym);
761     if (sle.sym)
762         return sle.sym;
763     auto t = type_alloc(TYint);
764     t.Tcount++;
765     auto s = symbol_calloc("internal");
766     s.Sclass = SC.static_;
767     s.Sfl = FLextern;
768     s.Sflags |= SFLnodebug;
769     s.Stype = t;
770     sle.sym = s;
771     auto dtb = DtBuilder(0);
772     Expression_toDt(sle, dtb);
773     s.Sdt = dtb.finish();
774     outdata(s);
775     return sle.sym;
776 }
777 
778 Symbol* toSymbol(ClassReferenceExp cre)
779 {
780     //printf("toSymbol() %p.value.sym: %p\n", cre, cre.value.sym);
781     if (cre.value.origin.sym)
782         return cre.value.origin.sym;
783     auto t = type_alloc(TYint);
784     t.Tcount++;
785     auto s = symbol_calloc("internal");
786     s.Sclass = SC.static_;
787     s.Sfl = FLextern;
788     s.Sflags |= SFLnodebug;
789     s.Stype = t;
790     cre.value.sym = s;
791     cre.value.origin.sym = s;
792     auto dtb = DtBuilder(0);
793     ClassReferenceExp_toInstanceDt(cre, dtb);
794     s.Sdt = dtb.finish();
795     outdata(s);
796     return cre.value.sym;
797 }
798 
799 /**************************************
800  * For C++ class cd, generate an instance of __cpp_type_info_ptr
801  * and populate it with a pointer to the C++ type info.
802  * Params:
803  *      cd = C++ class
804  * Returns:
805  *      symbol of instance of __cpp_type_info_ptr
806  */
807 Symbol* toSymbolCpp(ClassDeclaration cd)
808 {
809     assert(cd.isCPPclass());
810 
811     /* For the symbol std::exception, the type info is _ZTISt9exception
812      */
813     if (!cd.cpp_type_info_ptr_sym)
814     {
815         __gshared Symbol *scpp;
816         if (!scpp)
817             scpp = fake_classsym(Id.cpp_type_info_ptr);
818         Symbol *s = toSymbolX(cd, "_cpp_type_info_ptr", SC.comdat, scpp.Stype, "");
819         s.Sfl = FLdata;
820         s.Sflags |= SFLnodebug;
821         auto dtb = DtBuilder(0);
822         cpp_type_info_ptr_toDt(cd, dtb);
823         s.Sdt = dtb.finish();
824         outdata(s);
825         cd.cpp_type_info_ptr_sym = s;
826     }
827     return cd.cpp_type_info_ptr_sym;
828 }
829 
830 /**********************************
831  * Generate Symbol of C++ type info for C++ class cd.
832  * Params:
833  *      cd = C++ class
834  * Returns:
835  *      Symbol of cd's rtti type info
836  */
837 Symbol *toSymbolCppTypeInfo(ClassDeclaration cd)
838 {
839     const id = target.cpp.typeInfoMangle(cd);
840     auto s = symbol_calloc(id[0 .. strlen(id)]);
841     s.Sclass = SC.extern_;
842     s.Sfl = FLextern;          // C++ code will provide the definition
843     s.Sflags |= SFLnodebug;
844     auto t = type_fake(TYnptr);
845     t.Tcount++;
846     s.Stype = t;
847     return s;
848 }
849 
850 /**************************************
851  * Turn a class type into a C Symbol.
852  * Params:
853  *      t = class type
854  * Returns:
855  *      corresponding Symbol
856  */
857 
858 Symbol *toSymbol(Type t)
859 {
860     auto tc = t.isTypeClass();
861     assert(tc);
862     return toSymbol(tc.sym);
863 }
864 
865 /**********************************
866  * Converts a Loc to backend Srcpos
867  * Params:
868  *      loc = Source code location
869  * Returns:
870  *      Srcpos backend struct corresponding to the given location
871  */
872 Srcpos toSrcpos(Loc loc)
873 {
874     return Srcpos.create(loc.filename, loc.linnum, loc.charnum);
875 }