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