1 /** 2 * Do mangling for C++ linkage for Digital Mars C++ and Microsoft Visual C++. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: Walter Bright, https://www.digitalmars.com 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmanglewin.d, _cppmanglewin.d) 8 * Documentation: https://dlang.org/phobos/dmd_cppmanglewin.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cppmanglewin.d 10 */ 11 12 module dmd.cppmanglewin; 13 14 import core.stdc.string; 15 import core.stdc.stdio; 16 17 import dmd.arraytypes; 18 import dmd.astenums; 19 import dmd.cppmangle : isAggregateDtor, isCppOperator, CppOperator; 20 import dmd.dclass; 21 import dmd.declaration; 22 import dmd.denum : isSpecialEnumIdent; 23 import dmd.dstruct; 24 import dmd.dsymbol; 25 import dmd.dtemplate; 26 import dmd.errors; 27 import dmd.expression; 28 import dmd.func; 29 import dmd.globals; 30 import dmd.id; 31 import dmd.identifier; 32 import dmd.location; 33 import dmd.mtype; 34 import dmd.common.outbuffer; 35 import dmd.root.rootobject; 36 import dmd.target; 37 import dmd.tokens; 38 import dmd.typesem; 39 import dmd.visitor; 40 41 extern (C++): 42 43 44 const(char)* toCppMangleMSVC(Dsymbol s) 45 { 46 scope VisualCPPMangler v = new VisualCPPMangler(false, s.loc); 47 return v.mangleOf(s); 48 } 49 50 const(char)* cppTypeInfoMangleMSVC(Dsymbol s) 51 { 52 //printf("cppTypeInfoMangle(%s)\n", s.toChars()); 53 assert(0); 54 } 55 56 const(char)* toCppMangleDMC(Dsymbol s) 57 { 58 scope VisualCPPMangler v = new VisualCPPMangler(true, s.loc); 59 return v.mangleOf(s); 60 } 61 62 const(char)* cppTypeInfoMangleDMC(Dsymbol s) 63 { 64 //printf("cppTypeInfoMangle(%s)\n", s.toChars()); 65 assert(0); 66 } 67 68 /** 69 * Issues an ICE and returns true if `type` is shared or immutable 70 * 71 * Params: 72 * type = type to check 73 * 74 * Returns: 75 * true if type is shared or immutable 76 * false otherwise 77 */ 78 private extern (D) bool checkImmutableShared(Type type, Loc loc) 79 { 80 if (type.isImmutable() || type.isShared()) 81 { 82 error(loc, "internal compiler error: `shared` or `immutable` types cannot be mapped to C++ (%s)", type.toChars()); 83 fatal(); 84 return true; 85 } 86 return false; 87 } 88 89 private final class VisualCPPMangler : Visitor 90 { 91 alias visit = Visitor.visit; 92 Identifier[10] saved_idents; 93 Type[10] saved_types; 94 Loc loc; /// location for use in error messages 95 96 bool isNotTopType; /** When mangling one argument, we can call visit several times (for base types of arg type) 97 * but must save only arg type: 98 * For example: if we have an int** argument, we should save "int**" but visit will be called for "int**", "int*", "int" 99 * This flag is set up by the visit(NextType, ) function and should be reset when the arg type output is finished. 100 */ 101 bool ignoreConst; /// in some cases we should ignore CV-modifiers. 102 bool escape; /// toplevel const non-pointer types need a '$$C' escape in addition to a cv qualifier. 103 bool mangleReturnType; /// return type shouldn't be saved and substituted in arguments 104 bool isDmc; /// Digital Mars C++ name mangling 105 106 OutBuffer buf; 107 108 extern (D) this(VisualCPPMangler rvl) scope 109 { 110 saved_idents[] = rvl.saved_idents[]; 111 saved_types[] = rvl.saved_types[]; 112 isDmc = rvl.isDmc; 113 loc = rvl.loc; 114 } 115 116 public: 117 extern (D) this(bool isDmc, Loc loc) scope 118 { 119 saved_idents[] = null; 120 saved_types[] = null; 121 this.isDmc = isDmc; 122 this.loc = loc; 123 } 124 125 override void visit(Type type) 126 { 127 if (checkImmutableShared(type, loc)) 128 return; 129 130 error(loc, "internal compiler error: type `%s` cannot be mapped to C++\n", type.toChars()); 131 fatal(); //Fatal, because this error should be handled in frontend 132 } 133 134 override void visit(TypeNull type) 135 { 136 if (checkImmutableShared(type, loc)) 137 return; 138 if (checkTypeSaved(type)) 139 return; 140 141 buf.writestring("$$T"); 142 isNotTopType = false; 143 ignoreConst = false; 144 } 145 146 override void visit(TypeNoreturn type) 147 { 148 if (checkImmutableShared(type, loc)) 149 return; 150 if (checkTypeSaved(type)) 151 return; 152 153 buf.writeByte('X'); // yes, mangle it like `void` 154 isNotTopType = false; 155 ignoreConst = false; 156 } 157 158 override void visit(TypeBasic type) 159 { 160 //printf("visit(TypeBasic); is_not_top_type = %d\n", isNotTopType); 161 if (checkImmutableShared(type, loc)) 162 return; 163 164 if (type.isConst() && (isNotTopType || isDmc)) 165 { 166 if (checkTypeSaved(type)) 167 return; 168 } 169 if ((type.ty == Tbool) && checkTypeSaved(type)) // try to replace long name with number 170 { 171 return; 172 } 173 if (!isDmc) 174 { 175 switch (type.ty) 176 { 177 case Tint64: 178 case Tuns64: 179 case Tint128: 180 case Tuns128: 181 case Tfloat80: 182 case Twchar: 183 if (checkTypeSaved(type)) 184 return; 185 break; 186 187 default: 188 break; 189 } 190 } 191 mangleModifier(type); 192 switch (type.ty) 193 { 194 case Tvoid: 195 buf.writeByte('X'); 196 break; 197 case Tint8: 198 buf.writeByte('C'); 199 break; 200 case Tuns8: 201 buf.writeByte('E'); 202 break; 203 case Tint16: 204 buf.writeByte('F'); 205 break; 206 case Tuns16: 207 buf.writeByte('G'); 208 break; 209 case Tint32: 210 buf.writeByte('H'); 211 break; 212 case Tuns32: 213 buf.writeByte('I'); 214 break; 215 case Tfloat32: 216 buf.writeByte('M'); 217 break; 218 case Tint64: 219 buf.writestring("_J"); 220 break; 221 case Tuns64: 222 buf.writestring("_K"); 223 break; 224 case Tint128: 225 buf.writestring("_L"); 226 break; 227 case Tuns128: 228 buf.writestring("_M"); 229 break; 230 case Tfloat64: 231 buf.writeByte('N'); 232 break; 233 case Tfloat80: 234 if (isDmc) 235 buf.writestring("_Z"); // DigitalMars long double 236 else 237 buf.writestring("_T"); // Intel long double 238 break; 239 case Tbool: 240 buf.writestring("_N"); 241 break; 242 case Tchar: 243 buf.writeByte('D'); 244 break; 245 case Twchar: 246 buf.writestring("_S"); // Visual C++ char16_t (since C++11) 247 break; 248 case Tdchar: 249 buf.writestring("_U"); // Visual C++ char32_t (since C++11) 250 break; 251 default: 252 visit(cast(Type)type); 253 return; 254 } 255 isNotTopType = false; 256 ignoreConst = false; 257 } 258 259 override void visit(TypeVector type) 260 { 261 //printf("visit(TypeVector); is_not_top_type = %d\n", isNotTopType); 262 if (checkTypeSaved(type)) 263 return; 264 mangleModifier(type); 265 buf.writestring("T__m128@@"); // may be better as __m128i or __m128d? 266 isNotTopType = false; 267 ignoreConst = false; 268 } 269 270 override void visit(TypeSArray type) 271 { 272 // This method can be called only for static variable type mangling. 273 //printf("visit(TypeSArray); is_not_top_type = %d\n", isNotTopType); 274 if (checkTypeSaved(type)) 275 return; 276 // first dimension always mangled as const pointer 277 if (isDmc) 278 buf.writeByte('Q'); 279 else 280 buf.writeByte('P'); 281 isNotTopType = true; 282 assert(type.next); 283 if (type.next.ty == Tsarray) 284 { 285 mangleArray(cast(TypeSArray)type.next); 286 } 287 else 288 { 289 type.next.accept(this); 290 } 291 } 292 293 // attention: D int[1][2]* arr mapped to C++ int arr[][2][1]; (because it's more typical situation) 294 // There is not way to map int C++ (*arr)[2][1] to D 295 override void visit(TypePointer type) 296 { 297 //printf("visit(TypePointer); is_not_top_type = %d\n", isNotTopType); 298 if (checkImmutableShared(type, loc)) 299 return; 300 301 assert(type.next); 302 if (type.next.ty == Tfunction) 303 { 304 const(char)* arg = mangleFunctionType(cast(TypeFunction)type.next); // compute args before checking to save; args should be saved before function type 305 // If we've mangled this function early, previous call is meaningless. 306 // However we should do it before checking to save types of function arguments before function type saving. 307 // If this function was already mangled, types of all it arguments are save too, thus previous can't save 308 // anything if function is saved. 309 if (checkTypeSaved(type)) 310 return; 311 if (type.isConst()) 312 buf.writeByte('Q'); // const 313 else 314 buf.writeByte('P'); // mutable 315 buf.writeByte('6'); // pointer to a function 316 buf.writestring(arg); 317 isNotTopType = false; 318 ignoreConst = false; 319 return; 320 } 321 else if (type.next.ty == Tsarray) 322 { 323 if (checkTypeSaved(type)) 324 return; 325 mangleModifier(type); 326 if (type.isConst() || !isDmc) 327 buf.writeByte('Q'); // const 328 else 329 buf.writeByte('P'); // mutable 330 if (target.isLP64) 331 buf.writeByte('E'); 332 isNotTopType = true; 333 mangleArray(cast(TypeSArray)type.next); 334 return; 335 } 336 else 337 { 338 if (checkTypeSaved(type)) 339 return; 340 mangleModifier(type); 341 if (type.isConst()) 342 { 343 buf.writeByte('Q'); // const 344 } 345 else 346 { 347 buf.writeByte('P'); // mutable 348 } 349 if (target.isLP64) 350 buf.writeByte('E'); 351 isNotTopType = true; 352 type.next.accept(this); 353 } 354 } 355 356 override void visit(TypeReference type) 357 { 358 //printf("visit(TypeReference); type = %s\n", type.toChars()); 359 if (checkTypeSaved(type)) 360 return; 361 362 if (checkImmutableShared(type, loc)) 363 return; 364 365 buf.writeByte('A'); // mutable 366 if (target.isLP64) 367 buf.writeByte('E'); 368 isNotTopType = true; 369 assert(type.next); 370 if (type.next.ty == Tsarray) 371 { 372 mangleArray(cast(TypeSArray)type.next); 373 } 374 else 375 { 376 type.next.accept(this); 377 } 378 } 379 380 override void visit(TypeFunction type) 381 { 382 const(char)* arg = mangleFunctionType(type); 383 if (isDmc) 384 { 385 if (checkTypeSaved(type)) 386 return; 387 } 388 else 389 { 390 buf.writestring("$$A6"); 391 } 392 buf.writestring(arg); 393 isNotTopType = false; 394 ignoreConst = false; 395 } 396 397 override void visit(TypeStruct type) 398 { 399 if (checkTypeSaved(type)) 400 return; 401 //printf("visit(TypeStruct); is_not_top_type = %d\n", isNotTopType); 402 mangleModifier(type); 403 const agg = type.sym.isStructDeclaration(); 404 if (type.sym.isUnionDeclaration()) 405 buf.writeByte('T'); 406 else 407 buf.writeByte(agg.cppmangle == CPPMANGLE.asClass ? 'V' : 'U'); 408 mangleIdent(type.sym); 409 isNotTopType = false; 410 ignoreConst = false; 411 } 412 413 override void visit(TypeEnum type) 414 { 415 //printf("visit(TypeEnum); is_not_top_type = %d\n", cast(int)(flags & isNotTopType)); 416 const id = type.sym.ident; 417 string c; 418 if (id == Id.__c_long_double) 419 c = "O"; // VC++ long double 420 else if (id == Id.__c_long) 421 c = "J"; // VC++ long 422 else if (id == Id.__c_ulong) 423 c = "K"; // VC++ unsigned long 424 else if (id == Id.__c_longlong) 425 c = "_J"; // VC++ long long 426 else if (id == Id.__c_ulonglong) 427 c = "_K"; // VC++ unsigned long long 428 else if (id == Id.__c_char) 429 c = "D"; // VC++ char 430 else if (id == Id.__c_wchar_t) 431 { 432 c = isDmc ? "_Y" : "_W"; 433 } 434 435 if (c.length) 436 { 437 if (checkImmutableShared(type, loc)) 438 return; 439 440 if (type.isConst() && (isNotTopType || isDmc)) 441 { 442 if (checkTypeSaved(type)) 443 return; 444 } 445 mangleModifier(type); 446 buf.writestring(c); 447 } 448 else 449 { 450 if (checkTypeSaved(type)) 451 return; 452 mangleModifier(type); 453 buf.writestring("W4"); 454 mangleIdent(type.sym); 455 } 456 isNotTopType = false; 457 ignoreConst = false; 458 } 459 460 // D class mangled as pointer to C++ class 461 // const(Object) mangled as Object const* const 462 override void visit(TypeClass type) 463 { 464 //printf("visit(TypeClass); is_not_top_type = %d\n", isNotTopType); 465 if (checkTypeSaved(type)) 466 return; 467 if (isNotTopType) 468 mangleModifier(type); 469 if (type.isConst()) 470 buf.writeByte('Q'); 471 else 472 buf.writeByte('P'); 473 if (target.isLP64) 474 buf.writeByte('E'); 475 isNotTopType = true; 476 mangleModifier(type); 477 const cldecl = type.sym.isClassDeclaration(); 478 buf.writeByte(cldecl.cppmangle == CPPMANGLE.asStruct ? 'U' : 'V'); 479 mangleIdent(type.sym); 480 isNotTopType = false; 481 ignoreConst = false; 482 } 483 484 const(char)* mangleOf(Dsymbol s) 485 { 486 VarDeclaration vd = s.isVarDeclaration(); 487 FuncDeclaration fd = s.isFuncDeclaration(); 488 if (vd) 489 { 490 mangleVariable(vd); 491 } 492 else if (fd) 493 { 494 mangleFunction(fd); 495 } 496 else 497 { 498 assert(0); 499 } 500 return buf.extractChars(); 501 } 502 503 private: 504 extern(D): 505 506 void mangleFunction(FuncDeclaration d) 507 { 508 // <function mangle> ? <qualified name> <flags> <return type> <arg list> 509 assert(d); 510 buf.writeByte('?'); 511 mangleIdent(d); 512 if (d.needThis()) // <flags> ::= <virtual/protection flag> <const/volatile flag> <calling convention flag> 513 { 514 // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ 515 //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n", 516 //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual); 517 if ((d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) || (d.isDtorDeclaration() && d.parent.isClassDeclaration() && !d.isFinal())) 518 { 519 mangleVisibility(buf, d, "EMU"); 520 } 521 else 522 { 523 mangleVisibility(buf, d, "AIQ"); 524 } 525 if (target.isLP64) 526 buf.writeByte('E'); 527 if (d.type.isConst()) 528 { 529 buf.writeByte('B'); 530 } 531 else 532 { 533 buf.writeByte('A'); 534 } 535 } 536 else if (d.isMember2()) // static function 537 { 538 // <flags> ::= <virtual/protection flag> <calling convention flag> 539 mangleVisibility(buf, d, "CKS"); 540 } 541 else // top-level function 542 { 543 // <flags> ::= Y <calling convention flag> 544 buf.writeByte('Y'); 545 } 546 const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || isAggregateDtor(d)); 547 buf.writestring(args); 548 } 549 550 void mangleVariable(VarDeclaration d) 551 { 552 // <static variable mangle> ::= ? <qualified name> <protection flag> <const/volatile flag> <type> 553 assert(d); 554 // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 555 if (!(d.storage_class & (STC.extern_ | STC.field | STC.gshared))) 556 { 557 d.error("internal compiler error: C++ static non-__gshared non-extern variables not supported"); 558 fatal(); 559 } 560 buf.writeByte('?'); 561 mangleIdent(d); 562 assert((d.storage_class & STC.field) || !d.needThis()); 563 Dsymbol parent = d.toParent(); 564 while (parent && parent.isNspace()) 565 { 566 parent = parent.toParent(); 567 } 568 if (parent && parent.isModule()) // static member 569 { 570 buf.writeByte('3'); 571 } 572 else 573 { 574 mangleVisibility(buf, d, "012"); 575 } 576 Type t = d.type; 577 578 if (checkImmutableShared(t, loc)) 579 return; 580 581 const cv_mod = t.isConst() ? 'B' : 'A'; 582 if (t.ty != Tpointer) 583 t = t.mutableOf(); 584 t.accept(this); 585 if ((t.ty == Tpointer || t.ty == Treference || t.ty == Tclass) && target.isLP64) 586 { 587 buf.writeByte('E'); 588 } 589 buf.writeByte(cv_mod); 590 } 591 592 /** 593 * Mangles a template value 594 * 595 * Params: 596 * o = expression that represents the value 597 * tv = template value 598 * is_dmc_template = use DMC mangling 599 */ 600 void mangleTemplateValue(RootObject o, TemplateValueParameter tv, Dsymbol sym, bool is_dmc_template) 601 { 602 if (!tv.valType.isintegral()) 603 { 604 sym.error("internal compiler error: C++ %s template value parameter is not supported", tv.valType.toChars()); 605 fatal(); 606 return; 607 } 608 buf.writeByte('$'); 609 buf.writeByte('0'); 610 Expression e = isExpression(o); 611 assert(e); 612 if (tv.valType.isunsigned()) 613 { 614 mangleNumber(buf, e.toUInteger()); 615 } 616 else if (is_dmc_template) 617 { 618 // NOTE: DMC mangles everything based on 619 // unsigned int 620 mangleNumber(buf, e.toInteger()); 621 } 622 else 623 { 624 sinteger_t val = e.toInteger(); 625 if (val < 0) 626 { 627 val = -val; 628 buf.writeByte('?'); 629 } 630 mangleNumber(buf, val); 631 } 632 } 633 634 /** 635 * Mangles a template alias parameter 636 * 637 * Params: 638 * o = the alias value, a symbol or expression 639 */ 640 void mangleTemplateAlias(RootObject o, Dsymbol sym) 641 { 642 Dsymbol d = isDsymbol(o); 643 Expression e = isExpression(o); 644 645 if (d && d.isFuncDeclaration()) 646 { 647 buf.writeByte('$'); 648 buf.writeByte('1'); 649 mangleFunction(d.isFuncDeclaration()); 650 } 651 else if (e && e.op == EXP.variable && (cast(VarExp)e).var.isVarDeclaration()) 652 { 653 buf.writeByte('$'); 654 if (isDmc) 655 buf.writeByte('1'); 656 else 657 buf.writeByte('E'); 658 mangleVariable((cast(VarExp)e).var.isVarDeclaration()); 659 } 660 else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) 661 { 662 Dsymbol ds = d.isTemplateDeclaration().onemember; 663 if (isDmc) 664 { 665 buf.writeByte('V'); 666 } 667 else 668 { 669 if (ds.isUnionDeclaration()) 670 { 671 buf.writeByte('T'); 672 } 673 else if (ds.isStructDeclaration()) 674 { 675 buf.writeByte('U'); 676 } 677 else if (ds.isClassDeclaration()) 678 { 679 buf.writeByte('V'); 680 } 681 else 682 { 683 sym.error("internal compiler error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); 684 fatal(); 685 } 686 } 687 mangleIdent(d); 688 } 689 else 690 { 691 sym.error("internal compiler error: `%s` is unsupported parameter for C++ template", o.toChars()); 692 fatal(); 693 } 694 } 695 696 /** 697 * Mangles a template alias parameter 698 * 699 * Params: 700 * o = type 701 */ 702 void mangleTemplateType(RootObject o) 703 { 704 escape = true; 705 Type t = isType(o); 706 assert(t); 707 t.accept(this); 708 escape = false; 709 } 710 711 /** 712 * Mangles the name of a symbol 713 * 714 * Params: 715 * sym = symbol to mangle 716 * dont_use_back_reference = dont use back referencing 717 */ 718 void mangleName(Dsymbol sym, bool dont_use_back_reference) 719 { 720 //printf("mangleName('%s')\n", sym.toChars()); 721 bool is_dmc_template = false; 722 723 if (string s = mangleSpecialName(sym)) 724 { 725 buf.writestring(s); 726 return; 727 } 728 729 void writeName(Identifier name) 730 { 731 assert(name); 732 if (!is_dmc_template && dont_use_back_reference) 733 saveIdent(name); 734 else if (checkAndSaveIdent(name)) 735 return; 736 737 buf.writestring(name.toString()); 738 buf.writeByte('@'); 739 } 740 auto ti = sym.isTemplateInstance(); 741 if (!ti) 742 { 743 if (auto ag = sym.isAggregateDeclaration()) 744 { 745 if (ag.pMangleOverride) 746 { 747 writeName(ag.pMangleOverride.id); 748 return; 749 } 750 } 751 writeName(sym.ident); 752 return; 753 } 754 auto id = ti.tempdecl.ident; 755 auto symName = id.toString(); 756 757 int firstTemplateArg = 0; 758 759 // test for special symbols 760 if (mangleOperator(buf, ti,symName,firstTemplateArg)) 761 return; 762 TemplateInstance actualti = ti; 763 bool needNamespaces; 764 if (auto ag = ti.aliasdecl ? ti.aliasdecl.isAggregateDeclaration() : null) 765 { 766 if (ag.pMangleOverride) 767 { 768 if (ag.pMangleOverride.agg) 769 { 770 if (auto aggti = ag.pMangleOverride.agg.isInstantiated()) 771 actualti = aggti; 772 else 773 { 774 writeName(ag.pMangleOverride.id); 775 if (sym.parent && !sym.parent.needThis()) 776 for (auto ns = ag.pMangleOverride.agg.toAlias().cppnamespace; ns !is null && ns.ident !is null; ns = ns.cppnamespace) 777 writeName(ns.ident); 778 return; 779 } 780 id = ag.pMangleOverride.id; 781 symName = id.toString(); 782 needNamespaces = true; 783 } 784 else 785 { 786 writeName(ag.pMangleOverride.id); 787 for (auto ns = ti.toAlias().cppnamespace; ns !is null && ns.ident !is null; ns = ns.cppnamespace) 788 writeName(ns.ident); 789 return; 790 } 791 } 792 } 793 794 scope VisualCPPMangler tmp = new VisualCPPMangler(isDmc ? true : false, loc); 795 tmp.buf.writeByte('?'); 796 tmp.buf.writeByte('$'); 797 tmp.buf.writestring(symName); 798 tmp.saved_idents[0] = id; 799 if (symName == id.toString()) 800 tmp.buf.writeByte('@'); 801 if (isDmc) 802 { 803 tmp.mangleIdent(sym.parent, true); 804 is_dmc_template = true; 805 } 806 bool is_var_arg = false; 807 for (size_t i = firstTemplateArg; i < actualti.tiargs.length; i++) 808 { 809 RootObject o = (*actualti.tiargs)[i]; 810 TemplateParameter tp = null; 811 TemplateValueParameter tv = null; 812 TemplateTupleParameter tt = null; 813 if (!is_var_arg) 814 { 815 TemplateDeclaration td = actualti.tempdecl.isTemplateDeclaration(); 816 assert(td); 817 tp = (*td.parameters)[i]; 818 tv = tp.isTemplateValueParameter(); 819 tt = tp.isTemplateTupleParameter(); 820 } 821 if (tt) 822 { 823 is_var_arg = true; 824 tp = null; 825 } 826 if (tv) 827 { 828 tmp.mangleTemplateValue(o, tv, actualti, is_dmc_template); 829 } 830 else if (!tp || tp.isTemplateTypeParameter()) 831 { 832 Type t = isType(o); 833 if (t is null) 834 { 835 actualti.error("internal compiler error: C++ `%s` template value parameter is not supported", o.toChars()); 836 fatal(); 837 } 838 tmp.mangleTemplateType(o); 839 } 840 else if (tp.isTemplateAliasParameter()) 841 { 842 tmp.mangleTemplateAlias(o, actualti); 843 } 844 else 845 { 846 sym.error("internal compiler error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); 847 fatal(); 848 } 849 } 850 851 writeName(Identifier.idPool(tmp.buf.extractSlice())); 852 if (needNamespaces && actualti != ti) 853 { 854 for (auto ns = ti.toAlias().cppnamespace; ns !is null && ns.ident !is null; ns = ns.cppnamespace) 855 writeName(ns.ident); 856 } 857 } 858 859 // returns true if name already saved 860 bool checkAndSaveIdent(Identifier name) 861 { 862 foreach (i, ref id; saved_idents) 863 { 864 if (!id) // no saved same name 865 { 866 id = name; 867 break; 868 } 869 if (id == name) // ok, we've found same name. use index instead of name 870 { 871 buf.writeByte(cast(uint)i + '0'); 872 return true; 873 } 874 } 875 return false; 876 } 877 878 void saveIdent(Identifier name) 879 { 880 foreach (ref id; saved_idents) 881 { 882 if (!id) // no saved same name 883 { 884 id = name; 885 break; 886 } 887 if (id == name) // ok, we've found same name. use index instead of name 888 { 889 return; 890 } 891 } 892 } 893 894 void mangleIdent(Dsymbol sym, bool dont_use_back_reference = false) 895 { 896 // <qualified name> ::= <sub-name list> @ 897 // <sub-name list> ::= <sub-name> <name parts> 898 // ::= <sub-name> 899 // <sub-name> ::= <identifier> @ 900 // ::= ?$ <identifier> @ <template args> @ 901 // :: <back reference> 902 // <back reference> ::= 0-9 903 // <template args> ::= <template arg> <template args> 904 // ::= <template arg> 905 // <template arg> ::= <type> 906 // ::= $0<encoded integral number> 907 //printf("mangleIdent('%s')\n", sym.toChars()); 908 Dsymbol p = sym; 909 if (p.toParent() && p.toParent().isTemplateInstance()) 910 { 911 p = p.toParent(); 912 } 913 while (p && !p.isModule()) 914 { 915 mangleName(p, dont_use_back_reference); 916 // Mangle our string namespaces as well 917 for (auto ns = p.cppnamespace; ns !is null && ns.ident !is null; ns = ns.cppnamespace) 918 mangleName(ns, dont_use_back_reference); 919 920 p = p.toParent(); 921 if (p.toParent() && p.toParent().isTemplateInstance()) 922 { 923 p = p.toParent(); 924 } 925 } 926 if (!dont_use_back_reference) 927 buf.writeByte('@'); 928 } 929 930 bool checkTypeSaved(Type type) 931 { 932 if (isNotTopType) 933 return false; 934 if (mangleReturnType) 935 return false; 936 foreach (i, ref ty; saved_types) 937 { 938 if (!ty) // no saved same type 939 { 940 ty = type; 941 return false; 942 } 943 if (ty.equals(type)) // ok, we've found same type. use index instead of type 944 { 945 buf.writeByte(cast(uint)i + '0'); 946 isNotTopType = false; 947 ignoreConst = false; 948 return true; 949 } 950 } 951 return false; 952 } 953 954 void mangleModifier(Type type) 955 { 956 if (ignoreConst) 957 return; 958 if (checkImmutableShared(type, loc)) 959 return; 960 961 if (type.isConst()) 962 { 963 // Template parameters that are not pointers and are const need an $$C escape 964 // in addition to 'B' (const). 965 if (escape && type.ty != Tpointer) 966 buf.writestring("$$CB"); 967 else if (isNotTopType) 968 buf.writeByte('B'); // const 969 else if (isDmc && type.ty != Tpointer) 970 buf.writestring("_O"); 971 } 972 else if (isNotTopType) 973 buf.writeByte('A'); // mutable 974 975 escape = false; 976 } 977 978 void mangleArray(TypeSArray type) 979 { 980 mangleModifier(type); 981 size_t i = 0; 982 Type cur = type; 983 while (cur && cur.ty == Tsarray) 984 { 985 i++; 986 cur = cur.nextOf(); 987 } 988 buf.writeByte('Y'); 989 mangleNumber(buf, i); // count of dimensions 990 cur = type; 991 while (cur && cur.ty == Tsarray) // sizes of dimensions 992 { 993 TypeSArray sa = cast(TypeSArray)cur; 994 mangleNumber(buf, sa.dim ? sa.dim.toInteger() : 0); 995 cur = cur.nextOf(); 996 } 997 ignoreConst = true; 998 cur.accept(this); 999 } 1000 1001 const(char)* mangleFunctionType(TypeFunction type, bool needthis = false, bool noreturn = false) 1002 { 1003 scope VisualCPPMangler tmp = new VisualCPPMangler(this); 1004 // Calling convention 1005 if (target.isLP64) // always Microsoft x64 calling convention 1006 { 1007 tmp.buf.writeByte('A'); 1008 } 1009 else 1010 { 1011 final switch (type.linkage) 1012 { 1013 case LINK.c: 1014 tmp.buf.writeByte('A'); 1015 break; 1016 case LINK.cpp: 1017 if (needthis && type.parameterList.varargs != VarArg.variadic) 1018 tmp.buf.writeByte('E'); // thiscall 1019 else 1020 tmp.buf.writeByte('A'); // cdecl 1021 break; 1022 case LINK.windows: 1023 tmp.buf.writeByte('G'); // stdcall 1024 break; 1025 case LINK.d: 1026 case LINK.default_: 1027 case LINK.objc: 1028 tmp.visit(cast(Type)type); 1029 break; 1030 case LINK.system: 1031 assert(0); 1032 } 1033 } 1034 tmp.isNotTopType = false; 1035 if (noreturn) 1036 { 1037 tmp.buf.writeByte('@'); 1038 } 1039 else 1040 { 1041 Type rettype = type.next; 1042 if (type.isref) 1043 rettype = rettype.referenceTo(); 1044 ignoreConst = false; 1045 if (rettype.ty == Tstruct) 1046 { 1047 tmp.buf.writeByte('?'); 1048 tmp.buf.writeByte('A'); 1049 } 1050 else if (rettype.ty == Tenum) 1051 { 1052 const id = rettype.toDsymbol(null).ident; 1053 if (!isSpecialEnumIdent(id)) 1054 { 1055 tmp.buf.writeByte('?'); 1056 tmp.buf.writeByte('A'); 1057 } 1058 } 1059 tmp.mangleReturnType = true; 1060 rettype.accept(tmp); 1061 tmp.mangleReturnType = false; 1062 } 1063 if (!type.parameterList.parameters || !type.parameterList.parameters.length) 1064 { 1065 if (type.parameterList.varargs == VarArg.variadic) 1066 tmp.buf.writeByte('Z'); 1067 else 1068 tmp.buf.writeByte('X'); 1069 } 1070 else 1071 { 1072 foreach (n, p; type.parameterList) 1073 { 1074 Type t = p.type.merge2(); 1075 if (p.isReference()) 1076 t = t.referenceTo(); 1077 else if (p.isLazy()) 1078 { 1079 // Mangle as delegate 1080 auto tf = new TypeFunction(ParameterList(), t, LINK.d); 1081 auto td = new TypeDelegate(tf); 1082 t = td.merge(); 1083 } 1084 else if (Type cpptype = target.cpp.parameterType(t)) 1085 t = cpptype; 1086 if (t.ty == Tsarray) 1087 { 1088 error(loc, "internal compiler error: unable to pass static array to `extern(C++)` function."); 1089 errorSupplemental(loc, "Use pointer instead."); 1090 assert(0); 1091 } 1092 tmp.isNotTopType = false; 1093 ignoreConst = false; 1094 t.accept(tmp); 1095 } 1096 1097 if (type.parameterList.varargs == VarArg.variadic) 1098 { 1099 tmp.buf.writeByte('Z'); 1100 } 1101 else 1102 { 1103 tmp.buf.writeByte('@'); 1104 } 1105 } 1106 tmp.buf.writeByte('Z'); 1107 const(char)* ret = tmp.buf.extractChars(); 1108 saved_idents[] = tmp.saved_idents[]; 1109 saved_types[] = tmp.saved_types[]; 1110 return ret; 1111 } 1112 } 1113 1114 private: 1115 extern(D): 1116 1117 /** 1118 * Computes mangling for symbols with special mangling. 1119 * Params: 1120 * sym = symbol to mangle 1121 * Returns: 1122 * mangling for special symbols, 1123 * null if not a special symbol 1124 */ 1125 string mangleSpecialName(Dsymbol sym) 1126 { 1127 string mangle; 1128 if (sym.isCtorDeclaration()) 1129 mangle = "?0"; 1130 else if (sym.isAggregateDtor()) 1131 mangle = "?1"; 1132 else if (!sym.ident) 1133 return null; 1134 else if (sym.ident == Id.assign) 1135 mangle = "?4"; 1136 else if (sym.ident == Id.eq) 1137 mangle = "?8"; 1138 else if (sym.ident == Id.index) 1139 mangle = "?A"; 1140 else if (sym.ident == Id.call) 1141 mangle = "?R"; 1142 else if (sym.ident == Id.cppdtor) 1143 mangle = "?_G"; 1144 else 1145 return null; 1146 1147 return mangle; 1148 } 1149 1150 /** 1151 * Mangles an operator, if any 1152 * 1153 * Params: 1154 * buf = buffer to write mangling to 1155 * ti = associated template instance of the operator 1156 * symName = symbol name 1157 * firstTemplateArg = index if the first argument of the template (because the corresponding c++ operator is not a template) 1158 * Returns: 1159 * true if sym has no further mangling needed 1160 * false otherwise 1161 */ 1162 bool mangleOperator(ref OutBuffer buf, TemplateInstance ti, ref const(char)[] symName, ref int firstTemplateArg) 1163 { 1164 auto whichOp = isCppOperator(ti.name); 1165 final switch (whichOp) 1166 { 1167 case CppOperator.Unknown: 1168 return false; 1169 case CppOperator.Cast: 1170 buf.writestring("?B"); 1171 return true; 1172 case CppOperator.Assign: 1173 symName = "?4"; 1174 return false; 1175 case CppOperator.Eq: 1176 symName = "?8"; 1177 return false; 1178 case CppOperator.Index: 1179 symName = "?A"; 1180 return false; 1181 case CppOperator.Call: 1182 symName = "?R"; 1183 return false; 1184 1185 case CppOperator.Unary: 1186 case CppOperator.Binary: 1187 case CppOperator.OpAssign: 1188 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); 1189 assert(td); 1190 assert(ti.tiargs.length >= 1); 1191 TemplateParameter tp = (*td.parameters)[0]; 1192 TemplateValueParameter tv = tp.isTemplateValueParameter(); 1193 if (!tv || !tv.valType.isString()) 1194 return false; // expecting a string argument to operators! 1195 Expression exp = (*ti.tiargs)[0].isExpression(); 1196 StringExp str = exp.toStringExp(); 1197 switch (whichOp) 1198 { 1199 case CppOperator.Unary: 1200 switch (str.peekString()) 1201 { 1202 case "*": symName = "?D"; goto continue_template; 1203 case "++": symName = "?E"; goto continue_template; 1204 case "--": symName = "?F"; goto continue_template; 1205 case "-": symName = "?G"; goto continue_template; 1206 case "+": symName = "?H"; goto continue_template; 1207 case "~": symName = "?S"; goto continue_template; 1208 default: return false; 1209 } 1210 case CppOperator.Binary: 1211 switch (str.peekString()) 1212 { 1213 case ">>": symName = "?5"; goto continue_template; 1214 case "<<": symName = "?6"; goto continue_template; 1215 case "*": symName = "?D"; goto continue_template; 1216 case "-": symName = "?G"; goto continue_template; 1217 case "+": symName = "?H"; goto continue_template; 1218 case "&": symName = "?I"; goto continue_template; 1219 case "/": symName = "?K"; goto continue_template; 1220 case "%": symName = "?L"; goto continue_template; 1221 case "^": symName = "?T"; goto continue_template; 1222 case "|": symName = "?U"; goto continue_template; 1223 default: return false; 1224 } 1225 case CppOperator.OpAssign: 1226 switch (str.peekString()) 1227 { 1228 case "*": symName = "?X"; goto continue_template; 1229 case "+": symName = "?Y"; goto continue_template; 1230 case "-": symName = "?Z"; goto continue_template; 1231 case "/": symName = "?_0"; goto continue_template; 1232 case "%": symName = "?_1"; goto continue_template; 1233 case ">>": symName = "?_2"; goto continue_template; 1234 case "<<": symName = "?_3"; goto continue_template; 1235 case "&": symName = "?_4"; goto continue_template; 1236 case "|": symName = "?_5"; goto continue_template; 1237 case "^": symName = "?_6"; goto continue_template; 1238 default: return false; 1239 } 1240 default: assert(0); 1241 } 1242 } 1243 continue_template: 1244 if (ti.tiargs.length == 1) 1245 { 1246 buf.writestring(symName); 1247 return true; 1248 } 1249 firstTemplateArg = 1; 1250 return false; 1251 } 1252 1253 /**********************************' 1254 */ 1255 void mangleNumber(ref OutBuffer buf, dinteger_t num) 1256 { 1257 if (!num) // 0 encoded as "A@" 1258 { 1259 buf.writeByte('A'); 1260 buf.writeByte('@'); 1261 return; 1262 } 1263 if (num <= 10) // 5 encoded as "4" 1264 { 1265 buf.writeByte(cast(char)(num - 1 + '0')); 1266 return; 1267 } 1268 char[17] buff = void; 1269 buff[16] = 0; 1270 size_t i = 16; 1271 while (num) 1272 { 1273 --i; 1274 buff[i] = num % 16 + 'A'; 1275 num /= 16; 1276 } 1277 buf.writestring(&buff[i]); 1278 buf.writeByte('@'); 1279 } 1280 1281 /************************************* 1282 */ 1283 void mangleVisibility(ref OutBuffer buf, Declaration d, string privProtDef) 1284 { 1285 switch (d.visibility.kind) 1286 { 1287 case Visibility.Kind.private_: 1288 buf.writeByte(privProtDef[0]); 1289 break; 1290 case Visibility.Kind.protected_: 1291 buf.writeByte(privProtDef[1]); 1292 break; 1293 default: 1294 buf.writeByte(privProtDef[2]); 1295 break; 1296 } 1297 }