1 /** 2 * Does name mangling for `extern(D)` symbols. 3 * 4 * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling) 5 * 6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 7 * Authors: Walter Bright, https://www.digitalmars.com 8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d) 10 * Documentation: https://dlang.org/phobos/dmd_dmangle.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmangle.d 12 * References: https://dlang.org/blog/2017/12/20/ds-newfangled-name-mangling/ 13 */ 14 15 module dmd.dmangle; 16 17 18 /****************************************************************************** 19 * Returns exact mangled name of function. 20 */ 21 extern (C++) const(char)* mangleExact(FuncDeclaration fd) 22 { 23 //printf("mangleExact()\n"); 24 if (!fd.mangleString) 25 { 26 OutBuffer buf; 27 auto backref = Backref(null); 28 scope Mangler v = new Mangler(&buf, &backref); 29 v.mangleExact(fd); 30 fd.mangleString = buf.extractChars(); 31 } 32 return fd.mangleString; 33 } 34 35 extern (C++) void mangleToBuffer(Type t, OutBuffer* buf) 36 { 37 //printf("mangleToBuffer t()\n"); 38 if (t.deco) 39 buf.writestring(t.deco); 40 else 41 { 42 auto backref = Backref(t); 43 mangleType(t, 0, buf, backref); 44 //printf("%s\n", buf.peekChars()); 45 } 46 } 47 48 extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf) 49 { 50 //printf("mangleToBuffer e()\n"); 51 auto backref = Backref(null); 52 scope Mangler v = new Mangler(buf, &backref); 53 e.accept(v); 54 } 55 56 extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf) 57 { 58 //printf("mangleToBuffer s(%s)\n", s.toChars()); 59 auto backref = Backref(null); 60 scope Mangler v = new Mangler(buf, &backref); 61 s.accept(v); 62 } 63 64 extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf) 65 { 66 //printf("mangleToBuffer ti()\n"); 67 auto backref = Backref(null); 68 scope Mangler v = new Mangler(buf, &backref); 69 v.mangleTemplateInstance(ti); 70 } 71 72 /// Returns: `true` if the given character is a valid mangled character 73 package bool isValidMangling(dchar c) nothrow 74 { 75 return 76 c >= 'A' && c <= 'Z' || 77 c >= 'a' && c <= 'z' || 78 c >= '0' && c <= '9' || 79 c != 0 && strchr("$%().:?@[]_", c) || 80 isUniAlpha(c); 81 } 82 83 // valid mangled characters 84 unittest 85 { 86 assert('a'.isValidMangling); 87 assert('B'.isValidMangling); 88 assert('2'.isValidMangling); 89 assert('@'.isValidMangling); 90 assert('_'.isValidMangling); 91 } 92 93 // invalid mangled characters 94 unittest 95 { 96 assert(!'-'.isValidMangling); 97 assert(!0.isValidMangling); 98 assert(!'/'.isValidMangling); 99 assert(!'\\'.isValidMangling); 100 } 101 102 /********************************************** 103 * Convert a string representing a type (the deco) and 104 * return its equivalent Type. 105 * Params: 106 * deco = string containing the deco 107 * Returns: 108 * null for failed to convert 109 * Type for succeeded 110 */ 111 112 public Type decoToType(const(char)[] deco) 113 { 114 //printf("decoToType(): %.*s\n", cast(int)deco.length, deco.ptr); 115 if (auto sv = Type.stringtable.lookup(deco)) 116 { 117 if (sv.value) 118 { 119 Type t = cast(Type)sv.value; 120 assert(t.deco); 121 return t; 122 } 123 } 124 return null; 125 } 126 127 128 /***************************************** private ***************************************/ 129 130 private: 131 132 133 import core.stdc.ctype; 134 import core.stdc.stdio; 135 import core.stdc.string; 136 137 import dmd.aggregate; 138 import dmd.arraytypes; 139 import dmd.astenums; 140 import dmd.dclass; 141 import dmd.declaration; 142 import dmd.dmodule; 143 import dmd.dsymbol; 144 import dmd.dtemplate; 145 import dmd.expression; 146 import dmd.func; 147 import dmd.globals; 148 import dmd.id; 149 import dmd.identifier; 150 import dmd.mtype; 151 import dmd.root.ctfloat; 152 import dmd.common.outbuffer; 153 import dmd.root.aav; 154 import dmd.root.string; 155 import dmd.root.stringtable; 156 import dmd.root.utf; 157 import dmd.target; 158 import dmd.tokens; 159 import dmd.visitor; 160 161 private immutable char[TMAX] mangleChar = 162 [ 163 Tchar : 'a', 164 Tbool : 'b', 165 Tcomplex80 : 'c', 166 Tfloat64 : 'd', 167 Tfloat80 : 'e', 168 Tfloat32 : 'f', 169 Tint8 : 'g', 170 Tuns8 : 'h', 171 Tint32 : 'i', 172 Timaginary80 : 'j', 173 Tuns32 : 'k', 174 Tint64 : 'l', 175 Tuns64 : 'm', 176 Tnull : 'n', 177 Timaginary32 : 'o', 178 Timaginary64 : 'p', 179 Tcomplex32 : 'q', 180 Tcomplex64 : 'r', 181 Tint16 : 's', 182 Tuns16 : 't', 183 Twchar : 'u', 184 Tvoid : 'v', 185 Tdchar : 'w', 186 // x // const 187 // y // immutable 188 Tint128 : 'z', // zi 189 Tuns128 : 'z', // zk 190 191 Tarray : 'A', 192 Ttuple : 'B', 193 Tclass : 'C', 194 Tdelegate : 'D', 195 Tenum : 'E', 196 Tfunction : 'F', // D function 197 Tsarray : 'G', 198 Taarray : 'H', 199 // I // in 200 // J // out 201 // K // ref 202 // L // lazy 203 // M // has this, or scope 204 // N // Nh:vector Ng:wild Nn:noreturn 205 // O // shared 206 Tpointer : 'P', 207 // Q // Type/symbol/identifier backward reference 208 Treference : 'R', 209 Tstruct : 'S', 210 // T // Ttypedef 211 // U // C function 212 // W // Windows function 213 // X // variadic T t...) 214 // Y // variadic T t,...) 215 // Z // not variadic, end of parameters 216 217 // '@' shouldn't appear anywhere in the deco'd names 218 Tnone : '@', 219 Tident : '@', 220 Tinstance : '@', 221 Terror : '@', 222 Ttypeof : '@', 223 Tslice : '@', 224 Treturn : '@', 225 Tvector : '@', 226 Ttraits : '@', 227 Tmixin : '@', 228 Ttag : '@', 229 Tnoreturn : '@', // becomes 'Nn' 230 ]; 231 232 unittest 233 { 234 foreach (i, mangle; mangleChar) 235 { 236 if (mangle == char.init) 237 { 238 fprintf(stderr, "ty = %u\n", cast(uint)i); 239 assert(0); 240 } 241 } 242 } 243 244 /************************************************ 245 * Append the mangling of type `t` to `buf`. 246 * Params: 247 * t = type to mangle 248 * modMask = mod bits currently applying to t 249 * buf = buffer to append mangling to 250 * backref = state of back references (updated) 251 */ 252 void mangleType(Type t, ubyte modMask, OutBuffer* buf, ref Backref backref) 253 { 254 void visitWithMask(Type t, ubyte modMask) 255 { 256 void mangleSymbol(Dsymbol s) 257 { 258 scope Mangler v = new Mangler(buf, &backref); 259 v.mangleSymbol(s); 260 } 261 262 void visitType(Type t) 263 { 264 tyToDecoBuffer(buf, t.ty); 265 } 266 267 void visitTypeNext(TypeNext t) 268 { 269 visitType(t); 270 visitWithMask(t.next, t.mod); 271 } 272 273 void visitTypeVector(TypeVector t) 274 { 275 buf.writestring("Nh"); 276 visitWithMask(t.basetype, t.mod); 277 } 278 279 void visitTypeSArray(TypeSArray t) 280 { 281 visitType(t); 282 if (t.dim) 283 buf.print(t.dim.toInteger()); 284 if (t.next) 285 visitWithMask(t.next, t.mod); 286 } 287 288 void visitTypeDArray(TypeDArray t) 289 { 290 visitType(t); 291 if (t.next) 292 visitWithMask(t.next, t.mod); 293 } 294 295 void visitTypeAArray(TypeAArray t) 296 { 297 visitType(t); 298 visitWithMask(t.index, 0); 299 visitWithMask(t.next, t.mod); 300 } 301 302 void visitTypeFunction(TypeFunction t) 303 { 304 //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars()); 305 //static int nest; if (++nest == 50) *(char*)0=0; 306 mangleFuncType(t, t, t.mod, t.next, buf, backref); 307 } 308 309 void visitTypeIdentifier(TypeIdentifier t) 310 { 311 visitType(t); 312 auto name = t.ident.toString(); 313 buf.print(cast(int)name.length); 314 buf.writestring(name); 315 } 316 317 void visitTypeEnum(TypeEnum t) 318 { 319 visitType(t); 320 mangleSymbol(t.sym); 321 } 322 323 void visitTypeStruct(TypeStruct t) 324 { 325 //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name); 326 visitType(t); 327 mangleSymbol(t.sym); 328 } 329 330 void visitTypeClass(TypeClass t) 331 { 332 //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name); 333 visitType(t); 334 mangleSymbol(t.sym); 335 } 336 337 void visitTypeTuple(TypeTuple t) 338 { 339 //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars()); 340 visitType(t); 341 Parameter._foreach(t.arguments, (idx, param) { 342 mangleParameter(param, buf, backref); 343 return 0; 344 }); 345 buf.writeByte('Z'); 346 } 347 348 void visitTypeNull(TypeNull t) 349 { 350 visitType(t); 351 } 352 353 void visitTypeNoreturn(TypeNoreturn t) 354 { 355 buf.writestring("Nn"); 356 } 357 358 if (modMask != t.mod) 359 { 360 MODtoDecoBuffer(buf, t.mod); 361 } 362 if (backref.addRefToType(buf, t)) 363 return; 364 365 switch (t.ty) 366 { 367 case Tpointer: 368 case Treference: 369 case Tdelegate: 370 case Tslice: visitTypeNext (cast(TypeNext)t); break; 371 372 case Tarray: visitTypeDArray (t.isTypeDArray()); break; 373 case Tsarray: visitTypeSArray (t.isTypeSArray()); break; 374 case Taarray: visitTypeAArray (t.isTypeAArray()); break; 375 case Tfunction: visitTypeFunction (t.isTypeFunction()); break; 376 case Tident: visitTypeIdentifier(t.isTypeIdentifier()); break; 377 case Tclass: visitTypeClass (t.isTypeClass()); break; 378 case Tstruct: visitTypeStruct (t.isTypeStruct()); break; 379 case Tenum: visitTypeEnum (t.isTypeEnum()); break; 380 case Ttuple: visitTypeTuple (t.isTypeTuple()); break; 381 case Tnull: visitTypeNull (t.isTypeNull()); break; 382 case Tvector: visitTypeVector (t.isTypeVector()); break; 383 case Tnoreturn: visitTypeNoreturn (t.isTypeNoreturn); break; 384 385 case Terror: 386 break; // ignore errors 387 388 default: visitType(t); break; 389 } 390 } 391 392 visitWithMask(t, modMask); 393 } 394 395 396 /************************************************************* 397 */ 398 void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret, OutBuffer* buf, ref Backref backref) 399 { 400 //printf("mangleFuncType() %s\n", t.toChars()); 401 if (t.inuse && tret) 402 { 403 // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars()); 404 t.inuse = 2; // flag error to caller 405 return; 406 } 407 t.inuse++; 408 if (modMask != t.mod) 409 MODtoDecoBuffer(buf, t.mod); 410 411 char mc; 412 final switch (t.linkage) 413 { 414 case LINK.default_: 415 case LINK.d: 416 mc = 'F'; 417 break; 418 case LINK.c: 419 mc = 'U'; 420 break; 421 case LINK.windows: 422 mc = 'W'; 423 break; 424 case LINK.cpp: 425 mc = 'R'; 426 break; 427 case LINK.objc: 428 mc = 'Y'; 429 break; 430 case LINK.system: 431 assert(0); 432 } 433 buf.writeByte(mc); 434 435 if (ta.purity) 436 buf.writestring("Na"); 437 if (ta.isnothrow) 438 buf.writestring("Nb"); 439 if (ta.isref) 440 buf.writestring("Nc"); 441 if (ta.isproperty) 442 buf.writestring("Nd"); 443 if (ta.isnogc) 444 buf.writestring("Ni"); 445 446 // `return scope` must be in that order 447 if (ta.isreturnscope && !ta.isreturninferred) 448 { 449 buf.writestring("NjNl"); 450 } 451 else 452 { 453 // when return ref, the order is `scope return` 454 if (ta.isScopeQual && !ta.isscopeinferred) 455 buf.writestring("Nl"); 456 457 if (ta.isreturn && !ta.isreturninferred) 458 buf.writestring("Nj"); 459 } 460 461 if (ta.islive) 462 buf.writestring("Nm"); 463 464 switch (ta.trust) 465 { 466 case TRUST.trusted: 467 buf.writestring("Ne"); 468 break; 469 case TRUST.safe: 470 buf.writestring("Nf"); 471 break; 472 default: 473 break; 474 } 475 476 // Write argument types 477 foreach (idx, param; t.parameterList) 478 mangleParameter(param, buf, backref); 479 //if (buf.data[buf.length - 1] == '@') assert(0); 480 buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list 481 if (tret !is null) 482 mangleType(tret, 0, buf, backref); 483 t.inuse--; 484 } 485 486 /************************************************************* 487 */ 488 void mangleParameter(Parameter p, OutBuffer* buf, ref Backref backref) 489 { 490 // https://dlang.org/spec/abi.html#Parameter 491 492 auto stc = p.storageClass; 493 494 // Inferred storage classes don't get mangled in 495 if (stc & STC.scopeinferred) 496 stc &= ~(STC.scope_ | STC.scopeinferred); 497 if (stc & STC.returninferred) 498 stc &= ~(STC.return_ | STC.returninferred); 499 500 // much like hdrgen.stcToBuffer() 501 string rrs; 502 const isout = (stc & STC.out_) != 0; 503 final switch (buildScopeRef(stc)) 504 { 505 case ScopeRef.None: 506 case ScopeRef.Scope: 507 case ScopeRef.Ref: 508 case ScopeRef.Return: 509 case ScopeRef.RefScope: 510 break; 511 512 case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope 513 case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref 514 case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref 515 case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref 516 L1: 517 buf.writestring(rrs); 518 stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_); 519 break; 520 } 521 522 if (stc & STC.scope_) 523 buf.writeByte('M'); // scope 524 525 if (stc & STC.return_) 526 buf.writestring("Nk"); // return 527 528 switch (stc & (STC.IOR | STC.lazy_)) 529 { 530 case 0: 531 break; 532 case STC.in_: 533 buf.writeByte('I'); 534 break; 535 case STC.in_ | STC.ref_: 536 buf.writestring("IK"); 537 break; 538 case STC.out_: 539 buf.writeByte('J'); 540 break; 541 case STC.ref_: 542 buf.writeByte('K'); 543 break; 544 case STC.lazy_: 545 buf.writeByte('L'); 546 break; 547 default: 548 debug 549 { 550 printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_)); 551 } 552 assert(0); 553 } 554 mangleType(p.type, (stc & STC.in_) ? MODFlags.const_ : 0, buf, backref); 555 } 556 557 558 private extern (C++) final class Mangler : Visitor 559 { 560 alias visit = Visitor.visit; 561 public: 562 static assert(Key.sizeof == size_t.sizeof); 563 564 OutBuffer* buf; 565 Backref* backref; 566 567 extern (D) this(OutBuffer* buf, Backref* backref) 568 { 569 this.buf = buf; 570 this.backref = backref; 571 } 572 573 void mangleSymbol(Dsymbol s) 574 { 575 s.accept(this); 576 } 577 578 void mangleIdentifier(Identifier id, Dsymbol s) 579 { 580 if (!backref.addRefToIdentifier(buf, id)) 581 toBuffer(buf, id.toString(), s); 582 } 583 584 //////////////////////////////////////////////////////////////////////////// 585 void mangleDecl(Declaration sthis) 586 { 587 mangleParent(sthis); 588 assert(sthis.ident); 589 mangleIdentifier(sthis.ident, sthis); 590 if (FuncDeclaration fd = sthis.isFuncDeclaration()) 591 { 592 mangleFunc(fd, false); 593 } 594 else if (sthis.type) 595 { 596 mangleType(sthis.type, 0, buf, *backref); 597 } 598 else 599 assert(0); 600 } 601 602 void mangleParent(Dsymbol s) 603 { 604 //printf("mangleParent() %s %s\n", s.kind(), s.toChars()); 605 Dsymbol p; 606 if (TemplateInstance ti = s.isTemplateInstance()) 607 p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent; 608 else 609 p = s.parent; 610 if (p) 611 { 612 uint localNum = s.localNum; 613 mangleParent(p); 614 auto ti = p.isTemplateInstance(); 615 if (ti && !ti.isTemplateMixin()) 616 { 617 localNum = ti.tempdecl.localNum; 618 mangleTemplateInstance(ti); 619 } 620 else if (p.getIdent()) 621 { 622 mangleIdentifier(p.ident, s); 623 if (FuncDeclaration f = p.isFuncDeclaration()) 624 mangleFunc(f, true); 625 } 626 else 627 buf.writeByte('0'); 628 629 if (localNum) 630 writeLocalParent(buf, localNum); 631 } 632 } 633 634 void mangleFunc(FuncDeclaration fd, bool inParent) 635 { 636 //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null"); 637 //printf("fd.type = %s\n", fd.type.toChars()); 638 if (fd.needThis() || fd.isNested()) 639 buf.writeByte('M'); 640 641 if (!fd.type || fd.type.ty == Terror) 642 { 643 // never should have gotten here, but could be the result of 644 // failed speculative compilation 645 buf.writestring("9__error__FZ"); 646 647 //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars()); 648 //assert(0); // don't mangle function until semantic3 done. 649 } 650 else if (inParent) 651 { 652 TypeFunction tf = fd.type.isTypeFunction(); 653 TypeFunction tfo = fd.originalType.isTypeFunction(); 654 mangleFuncType(tf, tfo, 0, null, buf, *backref); 655 } 656 else 657 { 658 mangleType(fd.type, 0, buf, *backref); 659 } 660 } 661 662 override void visit(Declaration d) 663 { 664 //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", 665 // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage); 666 if (const id = externallyMangledIdentifier(d)) 667 { 668 buf.writestring(id); 669 return; 670 } 671 buf.writestring("_D"); 672 mangleDecl(d); 673 debug 674 { 675 const slice = (*buf)[]; 676 assert(slice.length); 677 for (size_t pos; pos < slice.length; ) 678 { 679 dchar c; 680 auto ppos = pos; 681 const s = utf_decodeChar(slice, pos, c); 682 assert(s is null, s); 683 assert(c.isValidMangling, "The mangled name '" ~ slice ~ "' " ~ 684 "contains an invalid character: " ~ slice[ppos..pos]); 685 } 686 } 687 } 688 689 /****************************************************************************** 690 * Normally FuncDeclaration and FuncAliasDeclaration have overloads. 691 * If and only if there is no overloads, mangle() could return 692 * exact mangled name. 693 * 694 * module test; 695 * void foo(long) {} // _D4test3fooFlZv 696 * void foo(string) {} // _D4test3fooFAyaZv 697 * 698 * // from FuncDeclaration.mangle(). 699 * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo" 700 * // by calling Dsymbol.mangle() 701 * 702 * // from FuncAliasDeclaration.mangle() 703 * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv" 704 * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv" 705 * 706 * If a function has no overloads, .mangleof property still returns exact mangled name. 707 * 708 * void bar() {} 709 * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv" 710 * // by calling FuncDeclaration.mangleExact(). 711 */ 712 override void visit(FuncDeclaration fd) 713 { 714 if (fd.isUnique()) 715 mangleExact(fd); 716 else 717 visit(cast(Dsymbol)fd); 718 } 719 720 // ditto 721 override void visit(FuncAliasDeclaration fd) 722 { 723 FuncDeclaration f = fd.toAliasFunc(); 724 FuncAliasDeclaration fa = f.isFuncAliasDeclaration(); 725 if (!fd.hasOverloads && !fa) 726 { 727 mangleExact(f); 728 return; 729 } 730 if (fa) 731 { 732 mangleSymbol(fa); 733 return; 734 } 735 visit(cast(Dsymbol)fd); 736 } 737 738 override void visit(OverDeclaration od) 739 { 740 if (od.overnext) 741 { 742 visit(cast(Dsymbol)od); 743 return; 744 } 745 if (FuncDeclaration fd = od.aliassym.isFuncDeclaration()) 746 { 747 if (fd.isUnique()) 748 { 749 mangleExact(fd); 750 return; 751 } 752 } 753 if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration()) 754 { 755 if (td.overnext is null) 756 { 757 mangleSymbol(td); 758 return; 759 } 760 } 761 visit(cast(Dsymbol)od); 762 } 763 764 void mangleExact(FuncDeclaration fd) 765 { 766 assert(!fd.isFuncAliasDeclaration()); 767 if (fd.mangleOverride) 768 { 769 buf.writestring(fd.mangleOverride); 770 return; 771 } 772 if (fd.isMain()) 773 { 774 buf.writestring("_Dmain"); 775 return; 776 } 777 if (fd.isWinMain() || fd.isDllMain()) 778 { 779 buf.writestring(fd.ident.toString()); 780 return; 781 } 782 visit(cast(Declaration)fd); 783 } 784 785 override void visit(VarDeclaration vd) 786 { 787 if (vd.mangleOverride) 788 { 789 buf.writestring(vd.mangleOverride); 790 return; 791 } 792 visit(cast(Declaration)vd); 793 } 794 795 override void visit(AggregateDeclaration ad) 796 { 797 ClassDeclaration cd = ad.isClassDeclaration(); 798 Dsymbol parentsave = ad.parent; 799 if (cd) 800 { 801 /* These are reserved to the compiler, so keep simple 802 * names for them. 803 */ 804 if (cd.ident == Id.Exception && cd.parent.ident == Id.object || cd.ident == Id.TypeInfo || cd.ident == Id.TypeInfo_Struct || cd.ident == Id.TypeInfo_Class || cd.ident == Id.TypeInfo_Tuple || cd == ClassDeclaration.object || cd == Type.typeinfoclass || cd == Module.moduleinfo || strncmp(cd.ident.toChars(), "TypeInfo_", 9) == 0) 805 { 806 // Don't mangle parent 807 ad.parent = null; 808 } 809 } 810 visit(cast(Dsymbol)ad); 811 ad.parent = parentsave; 812 } 813 814 override void visit(TemplateInstance ti) 815 { 816 version (none) 817 { 818 printf("TemplateInstance.mangle() %p %s", ti, ti.toChars()); 819 if (ti.parent) 820 printf(" parent = %s %s", ti.parent.kind(), ti.parent.toChars()); 821 printf("\n"); 822 } 823 if (!ti.tempdecl) 824 ti.error("is not defined"); 825 else 826 mangleParent(ti); 827 828 if (ti.isTemplateMixin() && ti.ident) 829 mangleIdentifier(ti.ident, ti); 830 else 831 mangleTemplateInstance(ti); 832 } 833 834 void mangleTemplateInstance(TemplateInstance ti) 835 { 836 TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration(); 837 assert(tempdecl); 838 839 // Use "__U" for the symbols declared inside template constraint. 840 const char T = ti.members ? 'T' : 'U'; 841 buf.printf("__%c", T); 842 mangleIdentifier(tempdecl.ident, tempdecl); 843 844 auto args = ti.tiargs; 845 size_t nparams = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0); 846 for (size_t i = 0; i < args.length; i++) 847 { 848 auto o = (*args)[i]; 849 Type ta = isType(o); 850 Expression ea = isExpression(o); 851 Dsymbol sa = isDsymbol(o); 852 Tuple va = isTuple(o); 853 //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); 854 if (i < nparams && (*tempdecl.parameters)[i].specialization()) 855 buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574 856 if (ta) 857 { 858 buf.writeByte('T'); 859 mangleType(ta, 0, buf, *backref); 860 } 861 else if (ea) 862 { 863 // Don't interpret it yet, it might actually be an alias template parameter. 864 // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339. 865 enum keepLvalue = true; 866 ea = ea.optimize(WANTvalue, keepLvalue); 867 if (auto ev = ea.isVarExp()) 868 { 869 sa = ev.var; 870 ea = null; 871 goto Lsa; 872 } 873 if (auto et = ea.isThisExp()) 874 { 875 sa = et.var; 876 ea = null; 877 goto Lsa; 878 } 879 if (auto ef = ea.isFuncExp()) 880 { 881 if (ef.td) 882 sa = ef.td; 883 else 884 sa = ef.fd; 885 ea = null; 886 goto Lsa; 887 } 888 buf.writeByte('V'); 889 if (ea.op == EXP.tuple) 890 { 891 ea.error("tuple is not a valid template value argument"); 892 continue; 893 } 894 // Now that we know it is not an alias, we MUST obtain a value 895 uint olderr = global.errors; 896 ea = ea.ctfeInterpret(); 897 if (ea.op == EXP.error || olderr != global.errors) 898 continue; 899 900 /* Use type mangling that matches what it would be for a function parameter 901 */ 902 mangleType(ea.type, 0, buf, *backref); 903 ea.accept(this); 904 } 905 else if (sa) 906 { 907 Lsa: 908 sa = sa.toAlias(); 909 if (sa.isDeclaration() && !sa.isOverDeclaration()) 910 { 911 Declaration d = sa.isDeclaration(); 912 913 if (auto fad = d.isFuncAliasDeclaration()) 914 d = fad.toAliasFunc(); 915 if (d.mangleOverride) 916 { 917 buf.writeByte('X'); 918 toBuffer(buf, d.mangleOverride, d); 919 continue; 920 } 921 if (const id = externallyMangledIdentifier(d)) 922 { 923 buf.writeByte('X'); 924 toBuffer(buf, id, d); 925 continue; 926 } 927 if (!d.type || !d.type.deco) 928 { 929 ti.error("forward reference of %s `%s`", d.kind(), d.toChars()); 930 continue; 931 } 932 } 933 buf.writeByte('S'); 934 mangleSymbol(sa); 935 } 936 else if (va) 937 { 938 assert(i + 1 == args.length); // must be last one 939 args = &va.objects; 940 i = -cast(size_t)1; 941 } 942 else 943 assert(0); 944 } 945 buf.writeByte('Z'); 946 } 947 948 override void visit(Dsymbol s) 949 { 950 version (none) 951 { 952 printf("Dsymbol.mangle() '%s'", s.toChars()); 953 if (s.parent) 954 printf(" parent = %s %s", s.parent.kind(), s.parent.toChars()); 955 printf("\n"); 956 } 957 if (s.parent && s.ident) 958 { 959 if (auto m = s.parent.isModule()) 960 { 961 if (m.filetype == FileType.c) 962 { 963 /* C types at global level get mangled into the __C global namespace 964 * to get the same mangling regardless of which module it 965 * is declared in. This works because types are the same if the mangling 966 * is the same. 967 */ 968 mangleIdentifier(Id.ImportC, s); // parent 969 mangleIdentifier(s.ident, s); 970 return; 971 } 972 } 973 } 974 mangleParent(s); 975 if (s.ident) 976 mangleIdentifier(s.ident, s); 977 else 978 toBuffer(buf, s.toString(), s); 979 //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id); 980 } 981 982 //////////////////////////////////////////////////////////////////////////// 983 override void visit(Expression e) 984 { 985 e.error("expression `%s` is not a valid template value argument", e.toChars()); 986 } 987 988 override void visit(IntegerExp e) 989 { 990 const v = e.toInteger(); 991 if (cast(sinteger_t)v < 0) 992 { 993 buf.writeByte('N'); 994 buf.print(-v); 995 } 996 else 997 { 998 buf.writeByte('i'); 999 buf.print(v); 1000 } 1001 } 1002 1003 override void visit(RealExp e) 1004 { 1005 buf.writeByte('e'); 1006 realToMangleBuffer(buf, e.value); 1007 } 1008 1009 override void visit(ComplexExp e) 1010 { 1011 buf.writeByte('c'); 1012 realToMangleBuffer(buf, e.toReal()); 1013 buf.writeByte('c'); // separate the two 1014 realToMangleBuffer(buf, e.toImaginary()); 1015 } 1016 1017 override void visit(NullExp e) 1018 { 1019 buf.writeByte('n'); 1020 } 1021 1022 override void visit(StringExp e) 1023 { 1024 char m; 1025 OutBuffer tmp; 1026 const(char)[] q; 1027 /* Write string in UTF-8 format 1028 */ 1029 switch (e.sz) 1030 { 1031 case 1: 1032 m = 'a'; 1033 q = e.peekString(); 1034 break; 1035 case 2: 1036 { 1037 m = 'w'; 1038 const slice = e.peekWstring(); 1039 for (size_t u = 0; u < e.len;) 1040 { 1041 dchar c; 1042 if (const s = utf_decodeWchar(slice, u, c)) 1043 e.error("%.*s", cast(int)s.length, s.ptr); 1044 else 1045 tmp.writeUTF8(c); 1046 } 1047 q = tmp[]; 1048 break; 1049 } 1050 case 4: 1051 { 1052 m = 'd'; 1053 const slice = e.peekDstring(); 1054 foreach (c; slice) 1055 { 1056 if (!utf_isValidDchar(c)) 1057 e.error("invalid UCS-32 char \\U%08x", c); 1058 else 1059 tmp.writeUTF8(c); 1060 } 1061 q = tmp[]; 1062 break; 1063 } 1064 1065 default: 1066 assert(0); 1067 } 1068 buf.reserve(1 + 11 + 2 * q.length); 1069 buf.writeByte(m); 1070 buf.print(q.length); 1071 buf.writeByte('_'); // nbytes <= 11 1072 auto slice = buf.allocate(2 * q.length); 1073 foreach (i, c; q) 1074 { 1075 char hi = (c >> 4) & 0xF; 1076 slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a'); 1077 char lo = c & 0xF; 1078 slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a'); 1079 } 1080 } 1081 1082 override void visit(ArrayLiteralExp e) 1083 { 1084 const dim = e.elements ? e.elements.length : 0; 1085 buf.writeByte('A'); 1086 buf.print(dim); 1087 foreach (i; 0 .. dim) 1088 { 1089 e[i].accept(this); 1090 } 1091 } 1092 1093 override void visit(AssocArrayLiteralExp e) 1094 { 1095 const dim = e.keys.length; 1096 buf.writeByte('A'); 1097 buf.print(dim); 1098 foreach (i; 0 .. dim) 1099 { 1100 (*e.keys)[i].accept(this); 1101 (*e.values)[i].accept(this); 1102 } 1103 } 1104 1105 override void visit(StructLiteralExp e) 1106 { 1107 const dim = e.elements ? e.elements.length : 0; 1108 buf.writeByte('S'); 1109 buf.print(dim); 1110 foreach (i; 0 .. dim) 1111 { 1112 Expression ex = (*e.elements)[i]; 1113 if (ex) 1114 ex.accept(this); 1115 else 1116 buf.writeByte('v'); // 'v' for void 1117 } 1118 } 1119 1120 override void visit(FuncExp e) 1121 { 1122 buf.writeByte('f'); 1123 if (e.td) 1124 mangleSymbol(e.td); 1125 else 1126 mangleSymbol(e.fd); 1127 } 1128 } 1129 1130 /*************************************** 1131 * Manage back reference mangling 1132 */ 1133 private struct Backref 1134 { 1135 /** 1136 * Back references a non-basic type 1137 * 1138 * The encoded mangling is 1139 * 'Q' <relative position of first occurrence of type> 1140 * 1141 * Params: 1142 * t = the type to encode via back referencing 1143 * 1144 * Returns: 1145 * true if the type was found. A back reference has been encoded. 1146 * false if the type was not found. The current position is saved for later back references. 1147 */ 1148 bool addRefToType(OutBuffer* buf, Type t) 1149 { 1150 if (t.isTypeBasic()) 1151 return false; 1152 1153 /** 1154 * https://issues.dlang.org/show_bug.cgi?id=21591 1155 * 1156 * Special case for unmerged TypeFunctions: use the generic merged 1157 * function type as backref cache key to avoid missed backrefs. 1158 * 1159 * Merging is based on mangling, so we need to avoid an infinite 1160 * recursion by excluding the case where `t` is the root type passed to 1161 * `mangleToBuffer()`. 1162 */ 1163 if (t != rootType) 1164 { 1165 if (t.isFunction_Delegate_PtrToFunction()) 1166 { 1167 t = t.merge2(); 1168 } 1169 } 1170 1171 return backrefImpl(buf, types, t); 1172 } 1173 1174 /** 1175 * Back references a single identifier 1176 * 1177 * The encoded mangling is 1178 * 'Q' <relative position of first occurrence of type> 1179 * 1180 * Params: 1181 * id = the identifier to encode via back referencing 1182 * 1183 * Returns: 1184 * true if the identifier was found. A back reference has been encoded. 1185 * false if the identifier was not found. The current position is saved for later back references. 1186 */ 1187 bool addRefToIdentifier(OutBuffer* buf, Identifier id) 1188 { 1189 return backrefImpl(buf, idents, id); 1190 } 1191 1192 private: 1193 1194 extern(D) bool backrefImpl(T)(OutBuffer* buf, ref AssocArray!(T, size_t) aa, T key) 1195 { 1196 auto p = aa.getLvalue(key); 1197 if (*p) 1198 { 1199 const offset = *p - 1; 1200 writeBackRef(buf, buf.length - offset); 1201 return true; 1202 } 1203 *p = buf.length + 1; 1204 return false; 1205 } 1206 1207 Type rootType; /// avoid infinite recursion 1208 AssocArray!(Type, size_t) types; /// Type => (offset+1) in buf 1209 AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf 1210 } 1211 1212 1213 /*********************** 1214 * Mangle basic type ty to buf. 1215 */ 1216 1217 private void tyToDecoBuffer(OutBuffer* buf, int ty) 1218 { 1219 const c = mangleChar[ty]; 1220 buf.writeByte(c); 1221 if (c == 'z') 1222 buf.writeByte(ty == Tint128 ? 'i' : 'k'); 1223 } 1224 1225 /********************************* 1226 * Mangling for mod. 1227 */ 1228 private void MODtoDecoBuffer(OutBuffer* buf, MOD mod) 1229 { 1230 switch (mod) 1231 { 1232 case 0: 1233 break; 1234 case MODFlags.const_: 1235 buf.writeByte('x'); 1236 break; 1237 case MODFlags.immutable_: 1238 buf.writeByte('y'); 1239 break; 1240 case MODFlags.shared_: 1241 buf.writeByte('O'); 1242 break; 1243 case MODFlags.shared_ | MODFlags.const_: 1244 buf.writestring("Ox"); 1245 break; 1246 case MODFlags.wild: 1247 buf.writestring("Ng"); 1248 break; 1249 case MODFlags.wildconst: 1250 buf.writestring("Ngx"); 1251 break; 1252 case MODFlags.shared_ | MODFlags.wild: 1253 buf.writestring("ONg"); 1254 break; 1255 case MODFlags.shared_ | MODFlags.wildconst: 1256 buf.writestring("ONgx"); 1257 break; 1258 default: 1259 assert(0); 1260 } 1261 } 1262 1263 1264 /** 1265 * writes a back reference with the relative position encoded with base 26 1266 * using upper case letters for all digits but the last digit which uses 1267 * a lower case letter. 1268 * The decoder has to look up the referenced position to determine 1269 * whether the back reference is an identifier (starts with a digit) 1270 * or a type (starts with a letter). 1271 * 1272 * Params: 1273 * buf = buffer to write to 1274 * pos = relative position to encode 1275 */ 1276 private 1277 void writeBackRef(OutBuffer* buf, size_t pos) 1278 { 1279 buf.writeByte('Q'); 1280 enum base = 26; 1281 size_t mul = 1; 1282 while (pos >= mul * base) 1283 mul *= base; 1284 while (mul >= base) 1285 { 1286 auto dig = cast(ubyte)(pos / mul); 1287 buf.writeByte('A' + dig); 1288 pos -= dig * mul; 1289 mul /= base; 1290 } 1291 buf.writeByte('a' + cast(ubyte)pos); 1292 } 1293 1294 1295 /************************************************************ 1296 * Write length prefixed string to buf. 1297 */ 1298 private 1299 extern (D) void toBuffer(OutBuffer* buf, const(char)[] id, Dsymbol s) 1300 { 1301 const len = id.length; 1302 if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone 1303 s.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf.length + len)); 1304 else 1305 { 1306 buf.print(len); 1307 buf.writestring(id); 1308 } 1309 } 1310 1311 1312 /***** 1313 * There can be multiple different declarations in the same 1314 * function that have the same mangled name. 1315 * This results in localNum having a non-zero number, which 1316 * is used to add a fake parent of the form `__Sddd` to make 1317 * the mangled names unique. 1318 * https://issues.dlang.org/show_bug.cgi?id=20565 1319 * Params: 1320 * buf = buffer to write to 1321 * localNum = local symbol number 1322 */ 1323 private 1324 void writeLocalParent(OutBuffer* buf, uint localNum) 1325 { 1326 uint ndigits = 1; 1327 auto n = localNum; 1328 while (n >= 10) 1329 { 1330 n /= 10; 1331 ++ndigits; 1332 } 1333 buf.printf("%u__S%u", ndigits + 3, localNum); 1334 } 1335 1336 /************************* 1337 * Write real to buffer. 1338 * Params: 1339 * buf = buffer to write to 1340 * value = real to write 1341 */ 1342 private 1343 void realToMangleBuffer(OutBuffer* buf, real_t value) 1344 { 1345 /* Rely on %A to get portable mangling. 1346 * Must munge result to get only identifier characters. 1347 * 1348 * Possible values from %A => mangled result 1349 * NAN => NAN 1350 * -INF => NINF 1351 * INF => INF 1352 * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 1353 * 0X1.9P+2 => 19P2 1354 */ 1355 if (CTFloat.isNaN(value)) 1356 { 1357 buf.writestring("NAN"); // no -NAN bugs 1358 return; 1359 } 1360 1361 if (value < CTFloat.zero) 1362 { 1363 buf.writeByte('N'); 1364 value = -value; 1365 } 1366 1367 if (CTFloat.isInfinity(value)) 1368 { 1369 buf.writestring("INF"); 1370 return; 1371 } 1372 1373 char[36] buffer = void; 1374 // 'A' format yields [-]0xh.hhhhp+-d 1375 const n = CTFloat.sprint(buffer.ptr, buffer.length, 'A', value); 1376 assert(n < buffer.length); 1377 foreach (const c; buffer[2 .. n]) 1378 { 1379 switch (c) 1380 { 1381 case '-': 1382 buf.writeByte('N'); 1383 break; 1384 1385 case '+': 1386 case '.': 1387 break; 1388 1389 default: 1390 buf.writeByte(c); 1391 break; 1392 } 1393 } 1394 } 1395 1396 /************************************************************ 1397 * Try to obtain an externally mangled identifier from a declaration. 1398 * If the declaration is at global scope or mixed in at global scope, 1399 * the user might want to call it externally, so an externally mangled 1400 * name is returned. Member functions or nested functions can't be called 1401 * externally in C, so in that case null is returned. C++ does support 1402 * namespaces, so extern(C++) always gives a C++ mangled name. 1403 * 1404 * See also: https://issues.dlang.org/show_bug.cgi?id=20012 1405 * 1406 * Params: 1407 * d = declaration to mangle 1408 * 1409 * Returns: 1410 * an externally mangled name or null if the declaration cannot be called externally 1411 */ 1412 private 1413 extern (D) const(char)[] externallyMangledIdentifier(Declaration d) 1414 { 1415 assert(!d.mangleOverride, "mangle overrides should have been handled earlier"); 1416 1417 const linkage = d.resolvedLinkage(); 1418 const par = d.toParent(); //toParent() skips over mixin templates 1419 if (!par || par.isModule() || linkage == LINK.cpp || 1420 (linkage == LINK.c && d.isCsymbol() && 1421 (d.isFuncDeclaration() || 1422 (d.isVarDeclaration() && d.isDataseg() && d.storage_class & STC.extern_)))) 1423 { 1424 if (linkage != LINK.d && d.localNum) 1425 d.error("the same declaration cannot be in multiple scopes with non-D linkage"); 1426 1427 final switch (linkage) 1428 { 1429 case LINK.d: 1430 break; 1431 case LINK.c: 1432 case LINK.windows: 1433 case LINK.objc: 1434 return d.ident.toString(); 1435 case LINK.cpp: 1436 { 1437 const p = target.cpp.toMangle(d); 1438 return p.toDString(); 1439 } 1440 case LINK.default_: 1441 d.error("forward declaration"); 1442 return d.ident.toString(); 1443 case LINK.system: 1444 assert(0); 1445 } 1446 } 1447 return null; 1448 }