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