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 }