1 /**
2  * Convert a D symbol to a symbol the linker understands (with mangled name).
3  *
4  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 http://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.rmem;
19 
20 import dmd.aggregate;
21 import dmd.arraytypes;
22 import dmd.complex;
23 import dmd.ctfeexpr;
24 import dmd.declaration;
25 import dmd.dclass;
26 import dmd.denum;
27 import dmd.dmodule;
28 import dmd.dstruct;
29 import dmd.dsymbol;
30 import dmd.dtemplate;
31 import dmd.e2ir;
32 import dmd.errors;
33 import dmd.expression;
34 import dmd.func;
35 import dmd.globals;
36 import dmd.glue;
37 import dmd.identifier;
38 import dmd.id;
39 import dmd.init;
40 import dmd.mtype;
41 import dmd.target;
42 import dmd.toctype;
43 import dmd.todt;
44 import dmd.tokens;
45 import dmd.typinf;
46 import dmd.visitor;
47 import dmd.dmangle;
48 
49 import dmd.backend.cdef;
50 import dmd.backend.cc;
51 import dmd.backend.dt;
52 import dmd.backend.type;
53 import dmd.backend.global;
54 import dmd.backend.oper;
55 import dmd.backend.cgcv;
56 import dmd.backend.ty;
57 
58 extern (C++):
59 
60 
61 /*************************************
62  * Helper
63  */
64 
65 Symbol *toSymbolX(Dsymbol ds, const(char)* prefix, int sclass, type *t, const(char)* suffix)
66 {
67     //printf("Dsymbol::toSymbolX('%s')\n", prefix);
68     import core.stdc.stdlib : malloc, free;
69     import dmd.root.outbuffer : OutBuffer;
70 
71     OutBuffer buf;
72     mangleToBuffer(ds, &buf);
73     size_t nlen = buf.length;
74     const(char)* n = buf.peekChars();
75     assert(n);
76 
77     import core.stdc.string : strlen;
78     size_t prefixlen = strlen(prefix);
79     size_t suffixlen = strlen(suffix);
80     size_t idlen = 2 + nlen + size_t.sizeof * 3 + prefixlen + suffixlen + 1;
81 
82     char[64] idbuf = void;
83     char *id = &idbuf[0];
84     if (idlen > idbuf.sizeof)
85     {
86         id = cast(char *)Mem.check(malloc(idlen));
87     }
88 
89     int nwritten = sprintf(id,"_D%.*s%d%.*s%.*s",
90         cast(int)nlen, n,
91         cast(int)prefixlen, cast(int)prefixlen, prefix,
92         cast(int)suffixlen, suffix);
93     assert(cast(uint)nwritten < idlen);         // nwritten does not include the terminating 0 char
94 
95     Symbol *s = symbol_name(id, nwritten, sclass, t);
96 
97     if (id != &idbuf[0])
98         free(id);
99 
100     //printf("-Dsymbol::toSymbolX() %s\n", id);
101     return s;
102 }
103 
104 private __gshared Symbol *scc;
105 
106 /*************************************
107  */
108 
109 Symbol *toSymbol(Dsymbol s)
110 {
111     extern (C++) static final class ToSymbol : Visitor
112     {
113         alias visit = Visitor.visit;
114 
115         Symbol *result;
116 
117         this()
118         {
119             result = null;
120         }
121 
122         override void visit(Dsymbol s)
123         {
124             printf("Dsymbol.toSymbol() '%s', kind = '%s'\n", s.toChars(), s.kind());
125             assert(0);          // BUG: implement
126         }
127 
128         override void visit(SymbolDeclaration sd)
129         {
130             result = toInitializer(sd.dsym);
131         }
132 
133         override void visit(VarDeclaration vd)
134         {
135             //printf("VarDeclaration.toSymbol(%s)\n", vd.toChars());
136             assert(!vd.needThis());
137 
138             const(char)[] id;
139             import dmd.root.outbuffer : OutBuffer;
140             OutBuffer buf;
141             bool isNRVO = false;
142             if (vd.isDataseg())
143             {
144                 mangleToBuffer(vd, &buf);
145                 id = buf.peekChars()[0..buf.length]; // symbol_calloc needs zero termination
146             }
147             else
148             {
149                 id = vd.ident.toString();
150                 if (FuncDeclaration fd = vd.toParent2().isFuncDeclaration())
151                 {
152                     if (fd.nrvo_can && fd.nrvo_var == vd)
153                     {
154                         buf.writestring("__nrvo_");
155                         buf.writestring(id);
156                         id = buf.peekChars()[0..buf.length]; // symbol_calloc needs zero termination
157                         isNRVO = true;
158                     }
159                 }
160             }
161             Symbol *s = symbol_calloc(id.ptr, cast(uint)id.length);
162             s.Salignment = vd.alignment;
163             if (vd.storage_class & STC.temp)
164                 s.Sflags |= SFLartifical;
165             if (isNRVO)
166                 s.Sflags |= SFLnodebug;
167 
168             TYPE *t;
169             if (vd.storage_class & (STC.out_ | STC.ref_))
170             {
171                 t = type_allocn(TYnref, Type_toCtype(vd.type));
172                 t.Tcount++;
173             }
174             else if (vd.storage_class & STC.lazy_)
175             {
176                 if (config.exe == EX_WIN64 && vd.isParameter())
177                     t = type_fake(TYnptr);
178                 else
179                     t = type_fake(TYdelegate);          // Tdelegate as C type
180                 t.Tcount++;
181             }
182             else if (vd.isParameter())
183             {
184                 if (ISX64REF(vd))
185                 {
186                     t = type_allocn(TYnref, Type_toCtype(vd.type));
187                     t.Tcount++;
188                 }
189                 else
190                 {
191                     t = Type_toCtype(vd.type);
192                     t.Tcount++;
193                 }
194             }
195             else
196             {
197                 t = Type_toCtype(vd.type);
198                 t.Tcount++;
199             }
200 
201             /* Even if a symbol is immutable, if it has a constructor then
202              * the constructor mutates it. Remember that constructors can
203              * be inlined into other code.
204              * Just can't rely on it being immutable.
205              */
206             if (t.Tty & (mTYimmutable | mTYconst))
207             {
208                 if (vd.ctorinit)
209                 {
210                     /* It was initialized in a constructor, so not really immutable
211                      * as far as the optimizer is concerned, as in this case:
212                      *   immutable int x;
213                      *   shared static this() { x += 3; }
214                      */
215                     t = type_setty(&t, t.Tty & ~(mTYimmutable | mTYconst));
216                 }
217                 else if (auto ts = vd.type.isTypeStruct())
218                 {
219                     if (!ts.isMutable() && ts.sym.ctor)
220                     {
221                         t = type_setty(&t, t.Tty & ~(mTYimmutable | mTYconst));
222                     }
223                 }
224                 else if (auto tc = vd.type.isTypeClass())
225                 {
226                     if (!tc.isMutable() && tc.sym.ctor)
227                     {
228                         t = type_setty(&t, t.Tty & ~(mTYimmutable | mTYconst));
229                     }
230                 }
231             }
232 
233             if (vd.isDataseg())
234             {
235                 if (vd.isThreadlocal() && !(vd.storage_class & STC.temp))
236                 {
237                     /* Thread local storage
238                      */
239                     auto ts = t;
240                     ts.Tcount++;   // make sure a different t is allocated
241                     type_setty(&t, t.Tty | mTYthread);
242                     ts.Tcount--;
243 
244                     if (config.objfmt == OBJ_MACH && _tysize[TYnptr] == 8)
245                         s.Salignment = 2;
246 
247                     if (global.params.vtls)
248                     {
249                         message(vd.loc, "`%s` is thread local", vd.toChars());
250                     }
251                 }
252                 s.Sclass = SCextern;
253                 s.Sfl = FLextern;
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                  *    http://msdn.microsoft.com/en-us/library/ff553493(VS.85).aspx
258                  */
259                 s.prettyIdent = vd.toPrettyChars(true);
260             }
261             else
262             {
263                 s.Sclass = SCauto;
264                 s.Sfl = FLauto;
265 
266                 if (vd.nestedrefs.dim)
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.linkage)
285             {
286                 case LINK.windows:
287                     m = global.params.is64bit ? mTYman_c : mTYman_std;
288                     break;
289 
290                 case LINK.pascal:
291                     m = mTYman_pas;
292                     break;
293 
294                 case LINK.objc:
295                 case LINK.c:
296                     m = mTYman_c;
297                     break;
298 
299                 case LINK.d:
300                     m = mTYman_d;
301                     break;
302 
303                 case LINK.cpp:
304                     s.Sflags |= SFLpublic;
305                     m = mTYman_cpp;
306                     break;
307 
308                 case LINK.default_:
309                 case LINK.system:
310                     printf("linkage = %d, vd = %s %s @ [%s]\n",
311                         vd.linkage, vd.kind(), vd.toChars(), vd.loc.toChars());
312                     assert(0);
313             }
314 
315             type_setmangle(&t, m);
316             s.Stype = t;
317 
318             s.lnoscopestart = vd.loc.linnum;
319             s.lnoscopeend = vd.endlinnum;
320             result = s;
321         }
322 
323         override void visit(TypeInfoDeclaration tid)
324         {
325             //printf("TypeInfoDeclaration.toSymbol(%s), linkage = %d\n", tid.toChars(), tid.linkage);
326             assert(tid.tinfo.ty != Terror);
327             visit(tid.isVarDeclaration());
328         }
329 
330         override void visit(TypeInfoClassDeclaration ticd)
331         {
332             //printf("TypeInfoClassDeclaration.toSymbol(%s), linkage = %d\n", ticd.toChars(), ticd.linkage);
333             ticd.tinfo.isTypeClass().sym.accept(this);
334         }
335 
336         override void visit(FuncAliasDeclaration fad)
337         {
338             fad.funcalias.accept(this);
339         }
340 
341         override void visit(FuncDeclaration fd)
342         {
343             const(char)* id = mangleExact(fd);
344 
345             //printf("FuncDeclaration.toSymbol(%s %s)\n", fd.kind(), fd.toChars());
346             //printf("\tid = '%s'\n", id);
347             //printf("\ttype = %s\n", fd.type.toChars());
348             auto s = symbol_calloc(id, cast(uint)strlen(id));
349 
350             s.prettyIdent = fd.toPrettyChars(true);
351             s.Sclass = SCglobal;
352             symbol_func(s);
353             func_t *f = s.Sfunc;
354             if (fd.isVirtual() && fd.vtblIndex != -1)
355                 f.Fflags |= Fvirtual;
356             else if (fd.isMember2() && fd.isStatic())
357                 f.Fflags |= Fstatic;
358 
359             f.Fstartline.set(fd.loc.filename, fd.loc.linnum, fd.loc.charnum);
360             if (fd.endloc.linnum)
361             {
362                 f.Fendline.set(fd.endloc.filename, fd.endloc.linnum, fd.endloc.charnum);
363             }
364             else
365             {
366                 f.Fendline = f.Fstartline;
367             }
368 
369             auto t = Type_toCtype(fd.type);
370             const msave = t.Tmangle;
371             if (fd.isMain())
372             {
373                 t.Tty = TYnfunc;
374                 t.Tmangle = mTYman_c;
375             }
376             else
377             {
378                 final switch (fd.linkage)
379                 {
380                     case LINK.windows:
381                         t.Tmangle = global.params.is64bit ? mTYman_c : mTYman_std;
382                         break;
383 
384                     case LINK.pascal:
385                         t.Tty = TYnpfunc;
386                         t.Tmangle = mTYman_pas;
387                         break;
388 
389                     case LINK.c:
390                     case LINK.objc:
391                         t.Tmangle = mTYman_c;
392                         break;
393 
394                     case LINK.d:
395                         t.Tmangle = mTYman_d;
396                         break;
397                     case LINK.cpp:
398                         s.Sflags |= SFLpublic;
399                         if (fd.isThis() && !global.params.is64bit && global.params.isWindows)
400                         {
401                             if ((cast(TypeFunction)fd.type).parameterList.varargs == VarArg.variadic)
402                             {
403                                 t.Tty = TYnfunc;
404                             }
405                             else
406                             {
407                                 t.Tty = TYmfunc;
408                             }
409                         }
410                         t.Tmangle = mTYman_cpp;
411                         break;
412                     case LINK.default_:
413                     case LINK.system:
414                         printf("linkage = %d\n", fd.linkage);
415                         assert(0);
416                 }
417             }
418 
419             if (msave)
420                 assert(msave == t.Tmangle);
421             //printf("Tty = %x, mangle = x%x\n", t.Tty, t.Tmangle);
422             t.Tcount++;
423             s.Stype = t;
424             //s.Sfielddef = this;
425 
426             result = s;
427         }
428 
429         static type* getClassInfoCType()
430         {
431             if (!scc)
432                 scc = fake_classsym(Id.ClassInfo);
433             return scc.Stype;
434         }
435 
436         /*************************************
437          * Create the "ClassInfo" symbol
438          */
439 
440         override void visit(ClassDeclaration cd)
441         {
442             auto s = toSymbolX(cd, "__Class", SCextern, getClassInfoCType(), "Z");
443             s.Sfl = FLextern;
444             s.Sflags |= SFLnodebug;
445             result = s;
446         }
447 
448         /*************************************
449          * Create the "InterfaceInfo" symbol
450          */
451 
452         override void visit(InterfaceDeclaration id)
453         {
454             auto s = toSymbolX(id, "__Interface", SCextern, getClassInfoCType(), "Z");
455             s.Sfl = FLextern;
456             s.Sflags |= SFLnodebug;
457             result = s;
458         }
459 
460         /*************************************
461          * Create the "ModuleInfo" symbol
462          */
463 
464         override void visit(Module m)
465         {
466             auto s = toSymbolX(m, "__ModuleInfo", SCextern, getClassInfoCType(), "Z");
467             s.Sfl = FLextern;
468             s.Sflags |= SFLnodebug;
469             result = s;
470         }
471     }
472 
473     if (s.csym)
474         return s.csym;
475 
476     scope ToSymbol v = new ToSymbol();
477     s.accept(v);
478     s.csym = v.result;
479     return v.result;
480 }
481 
482 
483 /*************************************
484  */
485 
486 Symbol *toImport(Symbol *sym)
487 {
488     //printf("Dsymbol.toImport('%s')\n", sym.Sident);
489     char *n = sym.Sident.ptr;
490     import core.stdc.stdlib : alloca;
491     char *id = cast(char *) alloca(6 + strlen(n) + 1 + type_paramsize(sym.Stype).sizeof*3 + 1);
492     int idlen;
493     if (config.exe != EX_WIN32 && config.exe != EX_WIN64)
494     {
495         id = n;
496         idlen = cast(int)strlen(n);
497     }
498     else if (sym.Stype.Tmangle == mTYman_std && tyfunc(sym.Stype.Tty))
499     {
500         if (config.exe == EX_WIN64)
501             idlen = sprintf(id,"__imp_%s",n);
502         else
503             idlen = sprintf(id,"_imp__%s@%u",n,cast(uint)type_paramsize(sym.Stype));
504     }
505     else
506     {
507         idlen = sprintf(id,(config.exe == EX_WIN64) ? "__imp_%s" : "_imp__%s",n);
508     }
509     auto t = type_alloc(TYnptr | mTYconst);
510     t.Tnext = sym.Stype;
511     t.Tnext.Tcount++;
512     t.Tmangle = mTYman_c;
513     t.Tcount++;
514     auto s = symbol_calloc(id, idlen);
515     s.Stype = t;
516     s.Sclass = SCextern;
517     s.Sfl = FLextern;
518     return s;
519 }
520 
521 /*********************************
522  * Generate import symbol from symbol.
523  */
524 
525 Symbol *toImport(Dsymbol ds)
526 {
527     if (!ds.isym)
528     {
529         if (!ds.csym)
530             ds.csym = toSymbol(ds);
531         ds.isym = toImport(ds.csym);
532     }
533     return ds.isym;
534 }
535 
536 /*************************************
537  * Thunks adjust the incoming 'this' pointer by 'offset'.
538  */
539 
540 Symbol *toThunkSymbol(FuncDeclaration fd, int offset)
541 {
542     Symbol *s = toSymbol(fd);
543     if (!offset)
544         return s;
545 
546     __gshared int tmpnum;
547     char[6 + tmpnum.sizeof * 3 + 1] name = void;
548 
549     sprintf(name.ptr,"_THUNK%d",tmpnum++);
550     auto sthunk = symbol_name(name.ptr,SCstatic,fd.csym.Stype);
551     sthunk.Sflags |= SFLnodebug | SFLartifical;
552     sthunk.Sflags |= SFLimplem;
553     outthunk(sthunk, fd.csym, 0, TYnptr, -offset, -1, 0);
554     return sthunk;
555 }
556 
557 
558 /**************************************
559  * Fake a struct symbol.
560  */
561 
562 Classsym *fake_classsym(Identifier id)
563 {
564     auto t = type_struct_class(id.toChars(),8,0,
565         null,null,
566         false, false, true, false);
567 
568     t.Ttag.Sstruct.Sflags = STRglobal;
569     t.Tflags |= TFsizeunknown | TFforward;
570     assert(t.Tmangle == 0);
571     t.Tmangle = mTYman_d;
572     return t.Ttag;
573 }
574 
575 /*************************************
576  * This is accessible via the ClassData, but since it is frequently
577  * needed directly (like for rtti comparisons), make it directly accessible.
578  */
579 
580 Symbol *toVtblSymbol(ClassDeclaration cd)
581 {
582     if (!cd.vtblsym || !cd.vtblsym.csym)
583     {
584         if (!cd.csym)
585             toSymbol(cd);
586 
587         auto t = type_allocn(TYnptr | mTYconst, tstypes[TYvoid]);
588         t.Tmangle = mTYman_d;
589         auto s = toSymbolX(cd, "__vtbl", SCextern, t, "Z");
590         s.Sflags |= SFLnodebug;
591         s.Sfl = FLextern;
592 
593         auto vtbl = cd.vtblSymbol();
594         vtbl.csym = s;
595     }
596     return cd.vtblsym.csym;
597 }
598 
599 /**********************************
600  * Create the static initializer for the struct/class.
601  */
602 
603 Symbol *toInitializer(AggregateDeclaration ad)
604 {
605     //printf("toInitializer() %s\n", ad.toChars());
606     if (!ad.sinit)
607     {
608         static structalign_t alignOf(Type t)
609         {
610             const explicitAlignment = t.alignment();
611             return explicitAlignment == STRUCTALIGN_DEFAULT ? t.alignsize() : explicitAlignment;
612         }
613 
614         auto sd = ad.isStructDeclaration();
615         if (sd &&
616             alignOf(sd.type) <= 16 &&
617             sd.type.size() <= 128 &&
618             sd.zeroInit &&
619             config.objfmt != OBJ_MACH && // same reason as in toobj.d toObjFile()
620             !(config.objfmt == OBJ_MSCOFF && !global.params.is64bit)) // -m32mscoff relocations are wrong
621         {
622             auto bzsave = bzeroSymbol;
623             ad.sinit = getBzeroSymbol();
624 
625             // Ensure emitted only once per object file
626             if (bzsave && bzeroSymbol != bzsave)
627                 assert(0);
628         }
629         else
630         {
631             auto stag = fake_classsym(Id.ClassInfo);
632             auto s = toSymbolX(ad, "__init", SCextern, stag.Stype, "Z");
633             s.Sfl = FLextern;
634             s.Sflags |= SFLnodebug;
635             if (sd)
636                 s.Salignment = sd.alignment;
637             ad.sinit = s;
638         }
639     }
640     return ad.sinit;
641 }
642 
643 Symbol *toInitializer(EnumDeclaration ed)
644 {
645     if (!ed.sinit)
646     {
647         auto stag = fake_classsym(Id.ClassInfo);
648         assert(ed.ident);
649         auto s = toSymbolX(ed, "__init", SCextern, stag.Stype, "Z");
650         s.Sfl = FLextern;
651         s.Sflags |= SFLnodebug;
652         ed.sinit = s;
653     }
654     return ed.sinit;
655 }
656 
657 
658 /********************************************
659  * Determine the right symbol to look up
660  * an associative array element.
661  * Input:
662  *      flags   0       don't add value signature
663  *              1       add value signature
664  */
665 
666 Symbol *aaGetSymbol(TypeAArray taa, const(char)* func, int flags)
667 {
668     assert((flags & ~1) == 0);
669 
670     // Dumb linear symbol table - should use associative array!
671     __gshared Symbol*[] sarray;
672 
673     //printf("aaGetSymbol(func = '%s', flags = %d, key = %p)\n", func, flags, key);
674     import core.stdc.stdlib : alloca;
675     auto id = cast(char *)alloca(3 + strlen(func) + 1);
676     const idlen = sprintf(id, "_aa%s", func);
677 
678     // See if symbol is already in sarray
679     foreach (s; sarray)
680     {
681         if (strcmp(id, s.Sident.ptr) == 0)
682         {
683             return s;                       // use existing Symbol
684         }
685     }
686 
687     // Create new Symbol
688 
689     auto s = symbol_calloc(id, idlen);
690     s.Sclass = SCextern;
691     s.Ssymnum = -1;
692     symbol_func(s);
693 
694     auto t = type_function(TYnfunc, null, false, Type_toCtype(taa.next));
695     t.Tmangle = mTYman_c;
696     s.Stype = t;
697 
698     sarray ~= s;                         // remember it
699     return s;
700 }
701 
702 /*****************************************************/
703 /*                   CTFE stuff                      */
704 /*****************************************************/
705 
706 Symbol* toSymbol(StructLiteralExp sle)
707 {
708     //printf("toSymbol() %p.sym: %p\n", sle, sle.sym);
709     if (sle.sym)
710         return sle.sym;
711     auto t = type_alloc(TYint);
712     t.Tcount++;
713     auto s = symbol_calloc("internal", 8);
714     s.Sclass = SCstatic;
715     s.Sfl = FLextern;
716     s.Sflags |= SFLnodebug;
717     s.Stype = t;
718     sle.sym = s;
719     auto dtb = DtBuilder(0);
720     Expression_toDt(sle, dtb);
721     s.Sdt = dtb.finish();
722     outdata(s);
723     return sle.sym;
724 }
725 
726 Symbol* toSymbol(ClassReferenceExp cre)
727 {
728     //printf("toSymbol() %p.value.sym: %p\n", cre, cre.value.sym);
729     if (cre.value.origin.sym)
730         return cre.value.origin.sym;
731     auto t = type_alloc(TYint);
732     t.Tcount++;
733     auto s = symbol_calloc("internal", 8);
734     s.Sclass = SCstatic;
735     s.Sfl = FLextern;
736     s.Sflags |= SFLnodebug;
737     s.Stype = t;
738     cre.value.sym = s;
739     cre.value.origin.sym = s;
740     auto dtb = DtBuilder(0);
741     ClassReferenceExp_toInstanceDt(cre, dtb);
742     s.Sdt = dtb.finish();
743     outdata(s);
744     return cre.value.sym;
745 }
746 
747 /**************************************
748  * For C++ class cd, generate an instance of __cpp_type_info_ptr
749  * and populate it with a pointer to the C++ type info.
750  * Params:
751  *      cd = C++ class
752  * Returns:
753  *      symbol of instance of __cpp_type_info_ptr
754  */
755 Symbol* toSymbolCpp(ClassDeclaration cd)
756 {
757     assert(cd.isCPPclass());
758 
759     /* For the symbol std::exception, the type info is _ZTISt9exception
760      */
761     if (!cd.cpp_type_info_ptr_sym)
762     {
763         __gshared Symbol *scpp;
764         if (!scpp)
765             scpp = fake_classsym(Id.cpp_type_info_ptr);
766         Symbol *s = toSymbolX(cd, "_cpp_type_info_ptr", SCcomdat, scpp.Stype, "");
767         s.Sfl = FLdata;
768         s.Sflags |= SFLnodebug;
769         auto dtb = DtBuilder(0);
770         cpp_type_info_ptr_toDt(cd, dtb);
771         s.Sdt = dtb.finish();
772         outdata(s);
773         cd.cpp_type_info_ptr_sym = s;
774     }
775     return cd.cpp_type_info_ptr_sym;
776 }
777 
778 /**********************************
779  * Generate Symbol of C++ type info for C++ class cd.
780  * Params:
781  *      cd = C++ class
782  * Returns:
783  *      Symbol of cd's rtti type info
784  */
785 Symbol *toSymbolCppTypeInfo(ClassDeclaration cd)
786 {
787     const id = target.cpp.typeInfoMangle(cd);
788     auto s = symbol_calloc(id, cast(uint)strlen(id));
789     s.Sclass = SCextern;
790     s.Sfl = FLextern;          // C++ code will provide the definition
791     s.Sflags |= SFLnodebug;
792     auto t = type_fake(TYnptr);
793     t.Tcount++;
794     s.Stype = t;
795     return s;
796 }