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