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