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