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