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