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 }