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