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