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