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