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