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