1 /** 2 * Compiler implementation of the $(LINK2 http://www.dlang.org, D programming language) 3 * 4 * Copyright: Copyright (c) 1999-2016 by Digital Mars, 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: $(DMDSRC _cppmangle.d) 8 */ 9 10 module ddmd.cppmangle; 11 12 import core.stdc..string; 13 import core.stdc.stdio; 14 15 import ddmd.arraytypes; 16 import ddmd.declaration; 17 import ddmd.dsymbol; 18 import ddmd.dtemplate; 19 import ddmd.errors; 20 import ddmd.expression; 21 import ddmd.func; 22 import ddmd.globals; 23 import ddmd.id; 24 import ddmd.mtype; 25 import ddmd.root.outbuffer; 26 import ddmd.root.rootobject; 27 import ddmd.target; 28 import ddmd.tokens; 29 import ddmd.visitor; 30 31 /* Do mangling for C++ linkage. 32 * No attempt is made to support mangling of templates, operator 33 * overloading, or special functions. 34 * 35 * So why don't we use the C++ ABI for D name mangling? 36 * Because D supports a lot of things (like modules) that the C++ 37 * ABI has no concept of. These affect every D mangled name, 38 * so nothing would be compatible anyway. 39 */ 40 static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) 41 { 42 /* 43 * Follows Itanium C++ ABI 1.86 44 */ 45 extern (C++) final class CppMangleVisitor : Visitor 46 { 47 alias visit = super.visit; 48 Objects components; 49 OutBuffer buf; 50 bool is_top_level; 51 bool components_on; 52 53 void writeBase36(size_t i) 54 { 55 if (i >= 36) 56 { 57 writeBase36(i / 36); 58 i %= 36; 59 } 60 if (i < 10) 61 buf.writeByte(cast(char)(i + '0')); 62 else if (i < 36) 63 buf.writeByte(cast(char)(i - 10 + 'A')); 64 else 65 assert(0); 66 } 67 68 bool substitute(RootObject p) 69 { 70 //printf("substitute %s\n", p ? p.toChars() : null); 71 if (components_on) 72 for (size_t i = 0; i < components.dim; i++) 73 { 74 //printf(" component[%d] = %s\n", i, components[i] ? components[i].toChars() : null); 75 if (p == components[i]) 76 { 77 //printf("\tmatch\n"); 78 /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... 79 */ 80 buf.writeByte('S'); 81 if (i) 82 writeBase36(i - 1); 83 buf.writeByte('_'); 84 return true; 85 } 86 } 87 return false; 88 } 89 90 bool exist(RootObject p) 91 { 92 //printf("exist %s\n", p ? p.toChars() : null); 93 if (components_on) 94 for (size_t i = 0; i < components.dim; i++) 95 { 96 if (p == components[i]) 97 { 98 return true; 99 } 100 } 101 return false; 102 } 103 104 void store(RootObject p) 105 { 106 //printf("store %s\n", p ? p.toChars() : "null"); 107 if (components_on) 108 components.push(p); 109 } 110 111 void source_name(Dsymbol s, bool skipname = false) 112 { 113 //printf("source_name(%s)\n", s.toChars()); 114 TemplateInstance ti = s.isTemplateInstance(); 115 if (ti) 116 { 117 if (!skipname && !substitute(ti.tempdecl)) 118 { 119 store(ti.tempdecl); 120 const(char)* name = ti.tempdecl.toAlias().ident.toChars(); 121 buf.printf("%d%s", strlen(name), name); 122 } 123 buf.writeByte('I'); 124 bool is_var_arg = false; 125 for (size_t i = 0; i < ti.tiargs.dim; i++) 126 { 127 RootObject o = cast(RootObject)(*ti.tiargs)[i]; 128 TemplateParameter tp = null; 129 TemplateValueParameter tv = null; 130 TemplateTupleParameter tt = null; 131 if (!is_var_arg) 132 { 133 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); 134 assert(td); 135 tp = (*td.parameters)[i]; 136 tv = tp.isTemplateValueParameter(); 137 tt = tp.isTemplateTupleParameter(); 138 } 139 /* 140 * <template-arg> ::= <type> # type or template 141 * ::= <expr-primary> # simple expressions 142 */ 143 if (tt) 144 { 145 buf.writeByte('I'); 146 is_var_arg = true; 147 tp = null; 148 } 149 if (tv) 150 { 151 // <expr-primary> ::= L <type> <value number> E # integer literal 152 if (tv.valType.isintegral()) 153 { 154 Expression e = isExpression(o); 155 assert(e); 156 buf.writeByte('L'); 157 tv.valType.accept(this); 158 if (tv.valType.isunsigned()) 159 { 160 buf.printf("%llu", e.toUInteger()); 161 } 162 else 163 { 164 sinteger_t val = e.toInteger(); 165 if (val < 0) 166 { 167 val = -val; 168 buf.writeByte('n'); 169 } 170 buf.printf("%lld", val); 171 } 172 buf.writeByte('E'); 173 } 174 else 175 { 176 s.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); 177 fatal(); 178 } 179 } 180 else if (!tp || tp.isTemplateTypeParameter()) 181 { 182 Type t = isType(o); 183 assert(t); 184 t.accept(this); 185 } 186 else if (tp.isTemplateAliasParameter()) 187 { 188 Dsymbol d = isDsymbol(o); 189 Expression e = isExpression(o); 190 if (!d && !e) 191 { 192 s.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); 193 fatal(); 194 } 195 if (d && d.isFuncDeclaration()) 196 { 197 bool is_nested = d.toParent() && !d.toParent().isModule() && (cast(TypeFunction)d.isFuncDeclaration().type).linkage == LINKcpp; 198 if (is_nested) 199 buf.writeByte('X'); 200 buf.writeByte('L'); 201 mangle_function(d.isFuncDeclaration()); 202 buf.writeByte('E'); 203 if (is_nested) 204 buf.writeByte('E'); 205 } 206 else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) 207 { 208 VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); 209 buf.writeByte('L'); 210 mangle_variable(vd, true); 211 buf.writeByte('E'); 212 } 213 else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) 214 { 215 if (!substitute(d)) 216 { 217 cpp_mangle_name(d, false); 218 } 219 } 220 else 221 { 222 s.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); 223 fatal(); 224 } 225 } 226 else 227 { 228 s.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); 229 fatal(); 230 } 231 } 232 if (is_var_arg) 233 { 234 buf.writeByte('E'); 235 } 236 buf.writeByte('E'); 237 return; 238 } 239 else 240 { 241 const(char)* name = s.ident.toChars(); 242 buf.printf("%d%s", strlen(name), name); 243 } 244 } 245 246 void prefix_name(Dsymbol s) 247 { 248 //printf("prefix_name(%s)\n", s.toChars()); 249 if (!substitute(s)) 250 { 251 Dsymbol p = s.toParent(); 252 if (p && p.isTemplateInstance()) 253 { 254 s = p; 255 if (exist(p.isTemplateInstance().tempdecl)) 256 { 257 p = null; 258 } 259 else 260 { 261 p = p.toParent(); 262 } 263 } 264 if (p && !p.isModule()) 265 { 266 if (p.ident == Id.std && is_initial_qualifier(p)) 267 buf.writestring("St"); 268 else 269 prefix_name(p); 270 } 271 if (!(s.ident == Id.std && is_initial_qualifier(s))) 272 store(s); 273 source_name(s); 274 } 275 } 276 277 /* Is s the initial qualifier? 278 */ 279 bool is_initial_qualifier(Dsymbol s) 280 { 281 Dsymbol p = s.toParent(); 282 if (p && p.isTemplateInstance()) 283 { 284 if (exist(p.isTemplateInstance().tempdecl)) 285 { 286 return true; 287 } 288 p = p.toParent(); 289 } 290 return !p || p.isModule(); 291 } 292 293 void cpp_mangle_name(Dsymbol s, bool qualified) 294 { 295 //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified); 296 Dsymbol p = s.toParent(); 297 Dsymbol se = s; 298 bool dont_write_prefix = false; 299 if (p && p.isTemplateInstance()) 300 { 301 se = p; 302 if (exist(p.isTemplateInstance().tempdecl)) 303 dont_write_prefix = true; 304 p = p.toParent(); 305 } 306 if (p && !p.isModule()) 307 { 308 /* The N..E is not required if: 309 * 1. the parent is 'std' 310 * 2. 'std' is the initial qualifier 311 * 3. there is no CV-qualifier or a ref-qualifier for a member function 312 * ABI 5.1.8 313 */ 314 if (p.ident == Id.std && is_initial_qualifier(p) && !qualified) 315 { 316 if (s.ident == Id.allocator) 317 { 318 buf.writestring("Sa"); // "Sa" is short for ::std::allocator 319 source_name(se, true); 320 } 321 else if (s.ident == Id.basic_string) 322 { 323 components_on = false; // turn off substitutions 324 buf.writestring("Sb"); // "Sb" is short for ::std::basic_string 325 size_t off = buf.offset; 326 source_name(se, true); 327 components_on = true; 328 // Replace ::std::basic_string < char, ::std::char_traits<char>, ::std::allocator<char> > 329 // with Ss 330 //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); 331 if (buf.offset - off >= 26 && memcmp(buf.data + off, "IcSt11char_traitsIcESaIcEE".ptr, 26) == 0) 332 { 333 buf.remove(off - 2, 28); 334 buf.insert(off - 2, "Ss"); 335 return; 336 } 337 buf.setsize(off); 338 source_name(se, true); 339 } 340 else if (s.ident == Id.basic_istream || s.ident == Id.basic_ostream || s.ident == Id.basic_iostream) 341 { 342 /* Replace 343 * ::std::basic_istream<char, std::char_traits<char> > with Si 344 * ::std::basic_ostream<char, std::char_traits<char> > with So 345 * ::std::basic_iostream<char, std::char_traits<char> > with Sd 346 */ 347 size_t off = buf.offset; 348 components_on = false; // turn off substitutions 349 source_name(se, true); 350 components_on = true; 351 //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); 352 if (buf.offset - off >= 21 && memcmp(buf.data + off, "IcSt11char_traitsIcEE".ptr, 21) == 0) 353 { 354 buf.remove(off, 21); 355 char[2] mbuf; 356 mbuf[0] = 'S'; 357 mbuf[1] = 'i'; 358 if (s.ident == Id.basic_ostream) 359 mbuf[1] = 'o'; 360 else if (s.ident == Id.basic_iostream) 361 mbuf[1] = 'd'; 362 buf.insert(off, mbuf[]); 363 return; 364 } 365 buf.setsize(off); 366 buf.writestring("St"); 367 source_name(se); 368 } 369 else 370 { 371 buf.writestring("St"); 372 source_name(se); 373 } 374 } 375 else 376 { 377 buf.writeByte('N'); 378 if (!dont_write_prefix) 379 prefix_name(p); 380 source_name(se); 381 buf.writeByte('E'); 382 } 383 } 384 else 385 source_name(se); 386 store(s); 387 } 388 389 void mangle_variable(VarDeclaration d, bool is_temp_arg_ref) 390 { 391 if (!(d.storage_class & (STCextern | STCgshared))) 392 { 393 d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); 394 fatal(); 395 } 396 Dsymbol p = d.toParent(); 397 if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" 398 { 399 buf.writestring("_ZN"); 400 prefix_name(p); 401 source_name(d); 402 buf.writeByte('E'); 403 } 404 else //char beta[6] should mangle as "beta" 405 { 406 if (!is_temp_arg_ref) 407 { 408 buf.writestring(d.ident.toChars()); 409 } 410 else 411 { 412 buf.writestring("_Z"); 413 source_name(d); 414 } 415 } 416 } 417 418 void mangle_function(FuncDeclaration d) 419 { 420 //printf("mangle_function(%s)\n", d.toChars()); 421 /* 422 * <mangled-name> ::= _Z <encoding> 423 * <encoding> ::= <function name> <bare-function-type> 424 * ::= <data name> 425 * ::= <special-name> 426 */ 427 TypeFunction tf = cast(TypeFunction)d.type; 428 buf.writestring("_Z"); 429 Dsymbol p = d.toParent(); 430 TemplateDeclaration ftd = getFuncTemplateDecl(d); 431 432 if (p && !p.isModule() && tf.linkage == LINKcpp && !ftd) 433 { 434 buf.writeByte('N'); 435 if (d.type.isConst()) 436 buf.writeByte('K'); 437 prefix_name(p); 438 // See ABI 5.1.8 Compression 439 // Replace ::std::allocator with Sa 440 if (buf.offset >= 17 && memcmp(buf.data, "_ZN3std9allocator".ptr, 17) == 0) 441 { 442 buf.remove(3, 14); 443 buf.insert(3, "Sa"); 444 } 445 // Replace ::std::basic_string with Sb 446 if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string".ptr, 21) == 0) 447 { 448 buf.remove(3, 18); 449 buf.insert(3, "Sb"); 450 } 451 // Replace ::std with St 452 if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std".ptr, 7) == 0) 453 { 454 buf.remove(3, 4); 455 buf.insert(3, "St"); 456 } 457 if (buf.offset >= 8 && memcmp(buf.data, "_ZNK3std".ptr, 8) == 0) 458 { 459 buf.remove(4, 4); 460 buf.insert(4, "St"); 461 } 462 if (d.isDtorDeclaration()) 463 { 464 buf.writestring("D1"); 465 } 466 else 467 { 468 source_name(d); 469 } 470 buf.writeByte('E'); 471 } 472 else if (ftd) 473 { 474 source_name(p); 475 this.is_top_level = true; 476 tf.nextOf().accept(this); 477 this.is_top_level = false; 478 } 479 else 480 { 481 source_name(d); 482 } 483 if (tf.linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling 484 { 485 assert(tf.ty == Tfunction); 486 argsCppMangle(tf.parameters, tf.varargs); 487 } 488 } 489 490 void argsCppMangle(Parameters* parameters, int varargs) 491 { 492 int paramsCppMangleDg(size_t n, Parameter fparam) 493 { 494 Type t = fparam.type.merge2(); 495 if (fparam.storageClass & (STCout | STCref)) 496 t = t.referenceTo(); 497 else if (fparam.storageClass & STClazy) 498 { 499 // Mangle as delegate 500 Type td = new TypeFunction(null, t, 0, LINKd); 501 td = new TypeDelegate(td); 502 t = t.merge(); 503 } 504 if (t.ty == Tsarray) 505 { 506 // Mangle static arrays as pointers 507 t.error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function."); 508 t.error(Loc(), "Use pointer instead."); 509 fatal(); 510 //t = t.nextOf().pointerTo(); 511 } 512 /* If it is a basic, enum or struct type, 513 * then don't mark it const 514 */ 515 this.is_top_level = true; 516 if ((t.ty == Tenum || t.ty == Tstruct || t.ty == Tpointer || t.isTypeBasic()) && t.isConst()) 517 t.mutableOf().accept(this); 518 else 519 t.accept(this); 520 this.is_top_level = false; 521 return 0; 522 } 523 524 if (parameters) 525 Parameter._foreach(parameters, ¶msCppMangleDg); 526 if (varargs) 527 buf.writestring("z"); 528 else if (!parameters || !parameters.dim) 529 buf.writeByte('v'); // encode ( ) parameters 530 } 531 532 public: 533 extern (D) this() 534 { 535 this.components_on = true; 536 } 537 538 const(char)* mangleOf(Dsymbol s) 539 { 540 VarDeclaration vd = s.isVarDeclaration(); 541 FuncDeclaration fd = s.isFuncDeclaration(); 542 if (vd) 543 { 544 mangle_variable(vd, false); 545 } 546 else if (fd) 547 { 548 mangle_function(fd); 549 } 550 else 551 { 552 assert(0); 553 } 554 Target.prefixName(&buf, LINKcpp); 555 return buf.extractString(); 556 } 557 558 override void visit(Type t) 559 { 560 if (t.isImmutable() || t.isShared()) 561 { 562 t.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", t.toChars()); 563 } 564 else 565 { 566 t.error(Loc(), "Internal Compiler Error: unsupported type %s\n", t.toChars()); 567 } 568 fatal(); //Fatal, because this error should be handled in frontend 569 } 570 571 override void visit(TypeBasic t) 572 { 573 /* ABI spec says: 574 * v void 575 * w wchar_t 576 * b bool 577 * c char 578 * a signed char 579 * h unsigned char 580 * s short 581 * t unsigned short 582 * i int 583 * j unsigned int 584 * l long 585 * m unsigned long 586 * x long long, __int64 587 * y unsigned long long, __int64 588 * n __int128 589 * o unsigned __int128 590 * f float 591 * d double 592 * e long double, __float80 593 * g __float128 594 * z ellipsis 595 * u <source-name> # vendor extended type 596 */ 597 char c; 598 char p = 0; 599 switch (t.ty) 600 { 601 case Tvoid: 602 c = 'v'; 603 break; 604 case Tint8: 605 c = 'a'; 606 break; 607 case Tuns8: 608 c = 'h'; 609 break; 610 case Tint16: 611 c = 's'; 612 break; 613 case Tuns16: 614 c = 't'; 615 break; 616 case Tint32: 617 c = 'i'; 618 break; 619 case Tuns32: 620 c = 'j'; 621 break; 622 case Tfloat32: 623 c = 'f'; 624 break; 625 case Tint64: 626 c = (Target.c_longsize == 8 ? 'l' : 'x'); 627 break; 628 case Tuns64: 629 c = (Target.c_longsize == 8 ? 'm' : 'y'); 630 break; 631 case Tint128: 632 c = 'n'; 633 break; 634 case Tuns128: 635 c = 'o'; 636 break; 637 case Tfloat64: 638 c = 'd'; 639 break; 640 case Tfloat80: 641 c = Target.realislongdouble ? 'e' : 'g'; 642 break; 643 case Tbool: 644 c = 'b'; 645 break; 646 case Tchar: 647 c = 'c'; 648 break; 649 case Twchar: 650 c = 't'; 651 break; 652 // unsigned short 653 case Tdchar: 654 c = 'w'; 655 break; 656 // wchar_t (UTF-32) 657 case Timaginary32: 658 p = 'G'; 659 c = 'f'; 660 break; 661 case Timaginary64: 662 p = 'G'; 663 c = 'd'; 664 break; 665 case Timaginary80: 666 p = 'G'; 667 c = 'e'; 668 break; 669 case Tcomplex32: 670 p = 'C'; 671 c = 'f'; 672 break; 673 case Tcomplex64: 674 p = 'C'; 675 c = 'd'; 676 break; 677 case Tcomplex80: 678 p = 'C'; 679 c = 'e'; 680 break; 681 default: 682 visit(cast(Type)t); 683 return; 684 } 685 if (t.isImmutable() || t.isShared()) 686 { 687 visit(cast(Type)t); 688 } 689 if (p || t.isConst()) 690 { 691 if (substitute(t)) 692 { 693 return; 694 } 695 else 696 { 697 store(t); 698 } 699 } 700 if (t.isConst()) 701 buf.writeByte('K'); 702 if (p) 703 buf.writeByte(p); 704 buf.writeByte(c); 705 } 706 707 override void visit(TypeVector t) 708 { 709 is_top_level = false; 710 if (substitute(t)) 711 return; 712 store(t); 713 if (t.isImmutable() || t.isShared()) 714 { 715 visit(cast(Type)t); 716 } 717 if (t.isConst()) 718 buf.writeByte('K'); 719 assert(t.basetype && t.basetype.ty == Tsarray); 720 assert((cast(TypeSArray)t.basetype).dim); 721 //buf.printf("Dv%llu_", ((TypeSArray *)t.basetype).dim.toInteger());// -- Gnu ABI v.4 722 buf.writestring("U8__vector"); //-- Gnu ABI v.3 723 t.basetype.nextOf().accept(this); 724 } 725 726 override void visit(TypeSArray t) 727 { 728 is_top_level = false; 729 if (!substitute(t)) 730 store(t); 731 if (t.isImmutable() || t.isShared()) 732 { 733 visit(cast(Type)t); 734 } 735 if (t.isConst()) 736 buf.writeByte('K'); 737 buf.printf("A%llu_", t.dim ? t.dim.toInteger() : 0); 738 t.next.accept(this); 739 } 740 741 override void visit(TypeDArray t) 742 { 743 visit(cast(Type)t); 744 } 745 746 override void visit(TypeAArray t) 747 { 748 visit(cast(Type)t); 749 } 750 751 override void visit(TypePointer t) 752 { 753 is_top_level = false; 754 if (substitute(t)) 755 return; 756 if (t.isImmutable() || t.isShared()) 757 { 758 visit(cast(Type)t); 759 } 760 if (t.isConst()) 761 buf.writeByte('K'); 762 buf.writeByte('P'); 763 t.next.accept(this); 764 store(t); 765 } 766 767 override void visit(TypeReference t) 768 { 769 is_top_level = false; 770 if (substitute(t)) 771 return; 772 buf.writeByte('R'); 773 t.next.accept(this); 774 store(t); 775 } 776 777 override void visit(TypeFunction t) 778 { 779 is_top_level = false; 780 /* 781 * <function-type> ::= F [Y] <bare-function-type> E 782 * <bare-function-type> ::= <signature type>+ 783 * # types are possible return type, then parameter types 784 */ 785 /* ABI says: 786 "The type of a non-static member function is considered to be different, 787 for the purposes of substitution, from the type of a namespace-scope or 788 static member function whose type appears similar. The types of two 789 non-static member functions are considered to be different, for the 790 purposes of substitution, if the functions are members of different 791 classes. In other words, for the purposes of substitution, the class of 792 which the function is a member is considered part of the type of 793 function." 794 795 BUG: Right now, types of functions are never merged, so our simplistic 796 component matcher always finds them to be different. 797 We should use Type.equals on these, and use different 798 TypeFunctions for non-static member functions, and non-static 799 member functions of different classes. 800 */ 801 if (substitute(t)) 802 return; 803 buf.writeByte('F'); 804 if (t.linkage == LINKc) 805 buf.writeByte('Y'); 806 Type tn = t.next; 807 if (t.isref) 808 tn = tn.referenceTo(); 809 tn.accept(this); 810 argsCppMangle(t.parameters, t.varargs); 811 buf.writeByte('E'); 812 store(t); 813 } 814 815 override void visit(TypeDelegate t) 816 { 817 visit(cast(Type)t); 818 } 819 820 override void visit(TypeStruct t) 821 { 822 const id = t.sym.ident; 823 //printf("struct id = '%s'\n", id.toChars()); 824 char c; 825 if (id == Id.__c_long) 826 c = 'l'; 827 else if (id == Id.__c_ulong) 828 c = 'm'; 829 else 830 c = 0; 831 if (c) 832 { 833 if (t.isImmutable() || t.isShared()) 834 { 835 visit(cast(Type)t); 836 } 837 if (t.isConst()) 838 { 839 if (substitute(t)) 840 { 841 return; 842 } 843 else 844 { 845 store(t); 846 } 847 } 848 if (t.isConst()) 849 buf.writeByte('K'); 850 buf.writeByte(c); 851 return; 852 } 853 is_top_level = false; 854 if (substitute(t)) 855 return; 856 if (t.isImmutable() || t.isShared()) 857 { 858 visit(cast(Type)t); 859 } 860 if (t.isConst()) 861 buf.writeByte('K'); 862 if (!substitute(t.sym)) 863 { 864 cpp_mangle_name(t.sym, t.isConst()); 865 } 866 if (t.isImmutable() || t.isShared()) 867 { 868 visit(cast(Type)t); 869 } 870 if (t.isConst()) 871 store(t); 872 } 873 874 override void visit(TypeEnum t) 875 { 876 is_top_level = false; 877 if (substitute(t)) 878 return; 879 if (t.isConst()) 880 buf.writeByte('K'); 881 if (!substitute(t.sym)) 882 { 883 cpp_mangle_name(t.sym, t.isConst()); 884 } 885 if (t.isImmutable() || t.isShared()) 886 { 887 visit(cast(Type)t); 888 } 889 if (t.isConst()) 890 store(t); 891 } 892 893 override void visit(TypeClass t) 894 { 895 if (substitute(t)) 896 return; 897 if (t.isImmutable() || t.isShared()) 898 { 899 visit(cast(Type)t); 900 } 901 if (t.isConst() && !is_top_level) 902 buf.writeByte('K'); 903 is_top_level = false; 904 buf.writeByte('P'); 905 if (t.isConst()) 906 buf.writeByte('K'); 907 if (!substitute(t.sym)) 908 { 909 cpp_mangle_name(t.sym, t.isConst()); 910 } 911 if (t.isConst()) 912 store(null); 913 store(t); 914 } 915 916 final const(char)* mangle_typeinfo(Dsymbol s) 917 { 918 buf.writestring("_ZTI"); 919 cpp_mangle_name(s, false); 920 return buf.extractString(); 921 } 922 } 923 924 extern (C++) const(char)* toCppMangle(Dsymbol s) 925 { 926 //printf("toCppMangle(%s)\n", s.toChars()); 927 scope CppMangleVisitor v = new CppMangleVisitor(); 928 return v.mangleOf(s); 929 } 930 931 extern (C++) const(char)* cppTypeInfoMangle(Dsymbol s) 932 { 933 //printf("cppTypeInfoMangle(%s)\n", s.toChars()); 934 scope CppMangleVisitor v = new CppMangleVisitor(); 935 return v.mangle_typeinfo(s); 936 } 937 } 938 else static if (TARGET_WINDOS) 939 { 940 // Windows DMC and Microsoft Visual C++ mangling 941 enum VC_SAVED_TYPE_CNT = 10u; 942 enum VC_SAVED_IDENT_CNT = 10u; 943 944 extern (C++) final class VisualCPPMangler : Visitor 945 { 946 alias visit = super.visit; 947 const(char)*[VC_SAVED_IDENT_CNT] saved_idents; 948 Type[VC_SAVED_TYPE_CNT] saved_types; 949 950 // IS_NOT_TOP_TYPE: when we mangling one argument, we can call visit several times (for base types of arg type) 951 // but we must save only arg type: 952 // For example: if we have an int** argument, we should save "int**" but visit will be called for "int**", "int*", "int" 953 // This flag is set up by the visit(NextType, ) function and should be reset when the arg type output is finished. 954 // MANGLE_RETURN_TYPE: return type shouldn't be saved and substituted in arguments 955 // IGNORE_CONST: in some cases we should ignore CV-modifiers. 956 957 enum Flags : int 958 { 959 IS_NOT_TOP_TYPE = 0x1, 960 MANGLE_RETURN_TYPE = 0x2, 961 IGNORE_CONST = 0x4, 962 IS_DMC = 0x8, 963 } 964 965 alias IS_NOT_TOP_TYPE = Flags.IS_NOT_TOP_TYPE; 966 alias MANGLE_RETURN_TYPE = Flags.MANGLE_RETURN_TYPE; 967 alias IGNORE_CONST = Flags.IGNORE_CONST; 968 alias IS_DMC = Flags.IS_DMC; 969 970 int flags; 971 OutBuffer buf; 972 973 extern (D) this(VisualCPPMangler rvl) 974 { 975 flags |= (rvl.flags & IS_DMC); 976 memcpy(&saved_idents, &rvl.saved_idents, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); 977 memcpy(&saved_types, &rvl.saved_types, Type.sizeof * VC_SAVED_TYPE_CNT); 978 } 979 980 public: 981 extern (D) this(bool isdmc) 982 { 983 if (isdmc) 984 { 985 flags |= IS_DMC; 986 } 987 memset(&saved_idents, 0, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); 988 memset(&saved_types, 0, Type.sizeof * VC_SAVED_TYPE_CNT); 989 } 990 991 override void visit(Type type) 992 { 993 if (type.isImmutable() || type.isShared()) 994 { 995 type.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", type.toChars()); 996 } 997 else 998 { 999 type.error(Loc(), "Internal Compiler Error: unsupported type %s\n", type.toChars()); 1000 } 1001 fatal(); //Fatal, because this error should be handled in frontend 1002 } 1003 1004 override void visit(TypeBasic type) 1005 { 1006 //printf("visit(TypeBasic); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); 1007 if (type.isImmutable() || type.isShared()) 1008 { 1009 visit(cast(Type)type); 1010 return; 1011 } 1012 if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) 1013 { 1014 if (checkTypeSaved(type)) 1015 return; 1016 } 1017 if ((type.ty == Tbool) && checkTypeSaved(type)) // try to replace long name with number 1018 { 1019 return; 1020 } 1021 if (!(flags & IS_DMC)) 1022 { 1023 switch (type.ty) 1024 { 1025 case Tint64: 1026 case Tuns64: 1027 case Tint128: 1028 case Tuns128: 1029 case Tfloat80: 1030 case Twchar: 1031 if (checkTypeSaved(type)) 1032 return; 1033 break; 1034 1035 default: 1036 break; 1037 } 1038 } 1039 mangleModifier(type); 1040 switch (type.ty) 1041 { 1042 case Tvoid: 1043 buf.writeByte('X'); 1044 break; 1045 case Tint8: 1046 buf.writeByte('C'); 1047 break; 1048 case Tuns8: 1049 buf.writeByte('E'); 1050 break; 1051 case Tint16: 1052 buf.writeByte('F'); 1053 break; 1054 case Tuns16: 1055 buf.writeByte('G'); 1056 break; 1057 case Tint32: 1058 buf.writeByte('H'); 1059 break; 1060 case Tuns32: 1061 buf.writeByte('I'); 1062 break; 1063 case Tfloat32: 1064 buf.writeByte('M'); 1065 break; 1066 case Tint64: 1067 buf.writestring("_J"); 1068 break; 1069 case Tuns64: 1070 buf.writestring("_K"); 1071 break; 1072 case Tint128: 1073 buf.writestring("_L"); 1074 break; 1075 case Tuns128: 1076 buf.writestring("_M"); 1077 break; 1078 case Tfloat64: 1079 buf.writeByte('N'); 1080 break; 1081 case Tbool: 1082 buf.writestring("_N"); 1083 break; 1084 case Tchar: 1085 buf.writeByte('D'); 1086 break; 1087 case Tdchar: 1088 buf.writeByte('I'); 1089 break; 1090 // unsigned int 1091 case Tfloat80: 1092 if (flags & IS_DMC) 1093 buf.writestring("_Z"); // DigitalMars long double 1094 else 1095 buf.writestring("_T"); // Intel long double 1096 break; 1097 case Twchar: 1098 if (flags & IS_DMC) 1099 buf.writestring("_Y"); // DigitalMars wchar_t 1100 else 1101 buf.writestring("_W"); // Visual C++ wchar_t 1102 break; 1103 default: 1104 visit(cast(Type)type); 1105 return; 1106 } 1107 flags &= ~IS_NOT_TOP_TYPE; 1108 flags &= ~IGNORE_CONST; 1109 } 1110 1111 override void visit(TypeVector type) 1112 { 1113 //printf("visit(TypeVector); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); 1114 if (checkTypeSaved(type)) 1115 return; 1116 buf.writestring("T__m128@@"); // may be better as __m128i or __m128d? 1117 flags &= ~IS_NOT_TOP_TYPE; 1118 flags &= ~IGNORE_CONST; 1119 } 1120 1121 override void visit(TypeSArray type) 1122 { 1123 // This method can be called only for static variable type mangling. 1124 //printf("visit(TypeSArray); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); 1125 if (checkTypeSaved(type)) 1126 return; 1127 // first dimension always mangled as const pointer 1128 if (flags & IS_DMC) 1129 buf.writeByte('Q'); 1130 else 1131 buf.writeByte('P'); 1132 flags |= IS_NOT_TOP_TYPE; 1133 assert(type.next); 1134 if (type.next.ty == Tsarray) 1135 { 1136 mangleArray(cast(TypeSArray)type.next); 1137 } 1138 else 1139 { 1140 type.next.accept(this); 1141 } 1142 } 1143 1144 // attention: D int[1][2]* arr mapped to C++ int arr[][2][1]; (because it's more typical situation) 1145 // There is not way to map int C++ (*arr)[2][1] to D 1146 override void visit(TypePointer type) 1147 { 1148 //printf("visit(TypePointer); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); 1149 if (type.isImmutable() || type.isShared()) 1150 { 1151 visit(cast(Type)type); 1152 return; 1153 } 1154 assert(type.next); 1155 if (type.next.ty == Tfunction) 1156 { 1157 const(char)* arg = mangleFunctionType(cast(TypeFunction)type.next); // compute args before checking to save; args should be saved before function type 1158 // If we've mangled this function early, previous call is meaningless. 1159 // However we should do it before checking to save types of function arguments before function type saving. 1160 // If this function was already mangled, types of all it arguments are save too, thus previous can't save 1161 // anything if function is saved. 1162 if (checkTypeSaved(type)) 1163 return; 1164 if (type.isConst()) 1165 buf.writeByte('Q'); // const 1166 else 1167 buf.writeByte('P'); // mutable 1168 buf.writeByte('6'); // pointer to a function 1169 buf.writestring(arg); 1170 flags &= ~IS_NOT_TOP_TYPE; 1171 flags &= ~IGNORE_CONST; 1172 return; 1173 } 1174 else if (type.next.ty == Tsarray) 1175 { 1176 if (checkTypeSaved(type)) 1177 return; 1178 mangleModifier(type); 1179 if (type.isConst() || !(flags & IS_DMC)) 1180 buf.writeByte('Q'); // const 1181 else 1182 buf.writeByte('P'); // mutable 1183 if (global.params.is64bit) 1184 buf.writeByte('E'); 1185 flags |= IS_NOT_TOP_TYPE; 1186 mangleArray(cast(TypeSArray)type.next); 1187 return; 1188 } 1189 else 1190 { 1191 if (checkTypeSaved(type)) 1192 return; 1193 mangleModifier(type); 1194 if (type.isConst()) 1195 { 1196 buf.writeByte('Q'); // const 1197 } 1198 else 1199 { 1200 buf.writeByte('P'); // mutable 1201 } 1202 if (global.params.is64bit) 1203 buf.writeByte('E'); 1204 flags |= IS_NOT_TOP_TYPE; 1205 type.next.accept(this); 1206 } 1207 } 1208 1209 override void visit(TypeReference type) 1210 { 1211 //printf("visit(TypeReference); type = %s\n", type.toChars()); 1212 if (checkTypeSaved(type)) 1213 return; 1214 if (type.isImmutable() || type.isShared()) 1215 { 1216 visit(cast(Type)type); 1217 return; 1218 } 1219 buf.writeByte('A'); // mutable 1220 if (global.params.is64bit) 1221 buf.writeByte('E'); 1222 flags |= IS_NOT_TOP_TYPE; 1223 assert(type.next); 1224 if (type.next.ty == Tsarray) 1225 { 1226 mangleArray(cast(TypeSArray)type.next); 1227 } 1228 else 1229 { 1230 type.next.accept(this); 1231 } 1232 } 1233 1234 override void visit(TypeFunction type) 1235 { 1236 const(char)* arg = mangleFunctionType(type); 1237 if ((flags & IS_DMC)) 1238 { 1239 if (checkTypeSaved(type)) 1240 return; 1241 } 1242 else 1243 { 1244 buf.writestring("$$A6"); 1245 } 1246 buf.writestring(arg); 1247 flags &= ~(IS_NOT_TOP_TYPE | IGNORE_CONST); 1248 } 1249 1250 override void visit(TypeStruct type) 1251 { 1252 const id = type.sym.ident; 1253 char c; 1254 if (id == Id.__c_long_double) 1255 c = 'O'; // VC++ long double 1256 else if (id == Id.__c_long) 1257 c = 'J'; // VC++ long 1258 else if (id == Id.__c_ulong) 1259 c = 'K'; // VC++ unsigned long 1260 else 1261 c = 0; 1262 if (c) 1263 { 1264 if (type.isImmutable() || type.isShared()) 1265 { 1266 visit(cast(Type)type); 1267 return; 1268 } 1269 if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) 1270 { 1271 if (checkTypeSaved(type)) 1272 return; 1273 } 1274 mangleModifier(type); 1275 buf.writeByte(c); 1276 } 1277 else 1278 { 1279 if (checkTypeSaved(type)) 1280 return; 1281 //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); 1282 mangleModifier(type); 1283 if (type.sym.isUnionDeclaration()) 1284 buf.writeByte('T'); 1285 else 1286 buf.writeByte(type.cppmangle == CPPMANGLE.asClass ? 'V' : 'U'); 1287 mangleIdent(type.sym); 1288 } 1289 flags &= ~IS_NOT_TOP_TYPE; 1290 flags &= ~IGNORE_CONST; 1291 } 1292 1293 override void visit(TypeEnum type) 1294 { 1295 //printf("visit(TypeEnum); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); 1296 if (checkTypeSaved(type)) 1297 return; 1298 mangleModifier(type); 1299 buf.writeByte('W'); 1300 switch (type.sym.memtype.ty) 1301 { 1302 case Tchar: 1303 case Tint8: 1304 buf.writeByte('0'); 1305 break; 1306 case Tuns8: 1307 buf.writeByte('1'); 1308 break; 1309 case Tint16: 1310 buf.writeByte('2'); 1311 break; 1312 case Tuns16: 1313 buf.writeByte('3'); 1314 break; 1315 case Tint32: 1316 buf.writeByte('4'); 1317 break; 1318 case Tuns32: 1319 buf.writeByte('5'); 1320 break; 1321 case Tint64: 1322 buf.writeByte('6'); 1323 break; 1324 case Tuns64: 1325 buf.writeByte('7'); 1326 break; 1327 default: 1328 visit(cast(Type)type); 1329 break; 1330 } 1331 mangleIdent(type.sym); 1332 flags &= ~IS_NOT_TOP_TYPE; 1333 flags &= ~IGNORE_CONST; 1334 } 1335 1336 // D class mangled as pointer to C++ class 1337 // const(Object) mangled as Object const* const 1338 override void visit(TypeClass type) 1339 { 1340 //printf("visit(TypeClass); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); 1341 if (checkTypeSaved(type)) 1342 return; 1343 if (flags & IS_NOT_TOP_TYPE) 1344 mangleModifier(type); 1345 if (type.isConst()) 1346 buf.writeByte('Q'); 1347 else 1348 buf.writeByte('P'); 1349 if (global.params.is64bit) 1350 buf.writeByte('E'); 1351 flags |= IS_NOT_TOP_TYPE; 1352 mangleModifier(type); 1353 buf.writeByte(type.cppmangle == CPPMANGLE.asStruct ? 'U' : 'V'); 1354 mangleIdent(type.sym); 1355 flags &= ~IS_NOT_TOP_TYPE; 1356 flags &= ~IGNORE_CONST; 1357 } 1358 1359 const(char)* mangleOf(Dsymbol s) 1360 { 1361 VarDeclaration vd = s.isVarDeclaration(); 1362 FuncDeclaration fd = s.isFuncDeclaration(); 1363 if (vd) 1364 { 1365 mangleVariable(vd); 1366 } 1367 else if (fd) 1368 { 1369 mangleFunction(fd); 1370 } 1371 else 1372 { 1373 assert(0); 1374 } 1375 return buf.extractString(); 1376 } 1377 1378 private: 1379 void mangleFunction(FuncDeclaration d) 1380 { 1381 // <function mangle> ? <qualified name> <flags> <return type> <arg list> 1382 assert(d); 1383 buf.writeByte('?'); 1384 mangleIdent(d); 1385 if (d.needThis()) // <flags> ::= <virtual/protection flag> <const/volatile flag> <calling convention flag> 1386 { 1387 // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ 1388 //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n", 1389 //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual); 1390 if (d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) 1391 { 1392 switch (d.protection.kind) 1393 { 1394 case PROTprivate: 1395 buf.writeByte('E'); 1396 break; 1397 case PROTprotected: 1398 buf.writeByte('M'); 1399 break; 1400 default: 1401 buf.writeByte('U'); 1402 break; 1403 } 1404 } 1405 else 1406 { 1407 switch (d.protection.kind) 1408 { 1409 case PROTprivate: 1410 buf.writeByte('A'); 1411 break; 1412 case PROTprotected: 1413 buf.writeByte('I'); 1414 break; 1415 default: 1416 buf.writeByte('Q'); 1417 break; 1418 } 1419 } 1420 if (global.params.is64bit) 1421 buf.writeByte('E'); 1422 if (d.type.isConst()) 1423 { 1424 buf.writeByte('B'); 1425 } 1426 else 1427 { 1428 buf.writeByte('A'); 1429 } 1430 } 1431 else if (d.isMember2()) // static function 1432 { 1433 // <flags> ::= <virtual/protection flag> <calling convention flag> 1434 switch (d.protection.kind) 1435 { 1436 case PROTprivate: 1437 buf.writeByte('C'); 1438 break; 1439 case PROTprotected: 1440 buf.writeByte('K'); 1441 break; 1442 default: 1443 buf.writeByte('S'); 1444 break; 1445 } 1446 } 1447 else // top-level function 1448 { 1449 // <flags> ::= Y <calling convention flag> 1450 buf.writeByte('Y'); 1451 } 1452 const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || d.isDtorDeclaration()); 1453 buf.writestring(args); 1454 } 1455 1456 void mangleVariable(VarDeclaration d) 1457 { 1458 // <static variable mangle> ::= ? <qualified name> <protection flag> <const/volatile flag> <type> 1459 assert(d); 1460 if (!(d.storage_class & (STCextern | STCgshared))) 1461 { 1462 d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); 1463 fatal(); 1464 } 1465 buf.writeByte('?'); 1466 mangleIdent(d); 1467 assert(!d.needThis()); 1468 if (d.parent && d.parent.isModule()) // static member 1469 { 1470 buf.writeByte('3'); 1471 } 1472 else 1473 { 1474 switch (d.protection.kind) 1475 { 1476 case PROTprivate: 1477 buf.writeByte('0'); 1478 break; 1479 case PROTprotected: 1480 buf.writeByte('1'); 1481 break; 1482 default: 1483 buf.writeByte('2'); 1484 break; 1485 } 1486 } 1487 char cv_mod = 0; 1488 Type t = d.type; 1489 if (t.isImmutable() || t.isShared()) 1490 { 1491 visit(t); 1492 return; 1493 } 1494 if (t.isConst()) 1495 { 1496 cv_mod = 'B'; // const 1497 } 1498 else 1499 { 1500 cv_mod = 'A'; // mutable 1501 } 1502 if (t.ty != Tpointer) 1503 t = t.mutableOf(); 1504 t.accept(this); 1505 if ((t.ty == Tpointer || t.ty == Treference || t.ty == Tclass) && global.params.is64bit) 1506 { 1507 buf.writeByte('E'); 1508 } 1509 buf.writeByte(cv_mod); 1510 } 1511 1512 void mangleName(Dsymbol sym, bool dont_use_back_reference = false) 1513 { 1514 //printf("mangleName('%s')\n", sym.toChars()); 1515 const(char)* name = null; 1516 bool is_dmc_template = false; 1517 if (sym.isDtorDeclaration()) 1518 { 1519 buf.writestring("?1"); 1520 return; 1521 } 1522 if (TemplateInstance ti = sym.isTemplateInstance()) 1523 { 1524 scope VisualCPPMangler tmp = new VisualCPPMangler((flags & IS_DMC) ? true : false); 1525 tmp.buf.writeByte('?'); 1526 tmp.buf.writeByte('$'); 1527 tmp.buf.writestring(ti.name.toChars()); 1528 tmp.saved_idents[0] = ti.name.toChars(); 1529 tmp.buf.writeByte('@'); 1530 if (flags & IS_DMC) 1531 { 1532 tmp.mangleIdent(sym.parent, true); 1533 is_dmc_template = true; 1534 } 1535 bool is_var_arg = false; 1536 for (size_t i = 0; i < ti.tiargs.dim; i++) 1537 { 1538 RootObject o = (*ti.tiargs)[i]; 1539 TemplateParameter tp = null; 1540 TemplateValueParameter tv = null; 1541 TemplateTupleParameter tt = null; 1542 if (!is_var_arg) 1543 { 1544 TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); 1545 assert(td); 1546 tp = (*td.parameters)[i]; 1547 tv = tp.isTemplateValueParameter(); 1548 tt = tp.isTemplateTupleParameter(); 1549 } 1550 if (tt) 1551 { 1552 is_var_arg = true; 1553 tp = null; 1554 } 1555 if (tv) 1556 { 1557 if (tv.valType.isintegral()) 1558 { 1559 tmp.buf.writeByte('$'); 1560 tmp.buf.writeByte('0'); 1561 Expression e = isExpression(o); 1562 assert(e); 1563 if (tv.valType.isunsigned()) 1564 { 1565 tmp.mangleNumber(e.toUInteger()); 1566 } 1567 else if (is_dmc_template) 1568 { 1569 // NOTE: DMC mangles everything based on 1570 // unsigned int 1571 tmp.mangleNumber(e.toInteger()); 1572 } 1573 else 1574 { 1575 sinteger_t val = e.toInteger(); 1576 if (val < 0) 1577 { 1578 val = -val; 1579 tmp.buf.writeByte('?'); 1580 } 1581 tmp.mangleNumber(val); 1582 } 1583 } 1584 else 1585 { 1586 sym.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); 1587 fatal(); 1588 } 1589 } 1590 else if (!tp || tp.isTemplateTypeParameter()) 1591 { 1592 Type t = isType(o); 1593 assert(t); 1594 t.accept(tmp); 1595 } 1596 else if (tp.isTemplateAliasParameter()) 1597 { 1598 Dsymbol d = isDsymbol(o); 1599 Expression e = isExpression(o); 1600 if (!d && !e) 1601 { 1602 sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); 1603 fatal(); 1604 } 1605 if (d && d.isFuncDeclaration()) 1606 { 1607 tmp.buf.writeByte('$'); 1608 tmp.buf.writeByte('1'); 1609 tmp.mangleFunction(d.isFuncDeclaration()); 1610 } 1611 else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) 1612 { 1613 tmp.buf.writeByte('$'); 1614 if (flags & IS_DMC) 1615 tmp.buf.writeByte('1'); 1616 else 1617 tmp.buf.writeByte('E'); 1618 tmp.mangleVariable((cast(VarExp)e).var.isVarDeclaration()); 1619 } 1620 else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) 1621 { 1622 Dsymbol ds = d.isTemplateDeclaration().onemember; 1623 if (flags & IS_DMC) 1624 { 1625 tmp.buf.writeByte('V'); 1626 } 1627 else 1628 { 1629 if (ds.isUnionDeclaration()) 1630 { 1631 tmp.buf.writeByte('T'); 1632 } 1633 else if (ds.isStructDeclaration()) 1634 { 1635 tmp.buf.writeByte('U'); 1636 } 1637 else if (ds.isClassDeclaration()) 1638 { 1639 tmp.buf.writeByte('V'); 1640 } 1641 else 1642 { 1643 sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); 1644 fatal(); 1645 } 1646 } 1647 tmp.mangleIdent(d); 1648 } 1649 else 1650 { 1651 sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); 1652 fatal(); 1653 } 1654 } 1655 else 1656 { 1657 sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); 1658 fatal(); 1659 } 1660 } 1661 name = tmp.buf.extractString(); 1662 } 1663 else 1664 { 1665 name = sym.ident.toChars(); 1666 } 1667 assert(name); 1668 if (is_dmc_template) 1669 { 1670 if (checkAndSaveIdent(name)) 1671 return; 1672 } 1673 else 1674 { 1675 if (dont_use_back_reference) 1676 { 1677 saveIdent(name); 1678 } 1679 else 1680 { 1681 if (checkAndSaveIdent(name)) 1682 return; 1683 } 1684 } 1685 buf.writestring(name); 1686 buf.writeByte('@'); 1687 } 1688 1689 // returns true if name already saved 1690 bool checkAndSaveIdent(const(char)* name) 1691 { 1692 foreach (i; 0 .. VC_SAVED_IDENT_CNT) 1693 { 1694 if (!saved_idents[i]) // no saved same name 1695 { 1696 saved_idents[i] = name; 1697 break; 1698 } 1699 if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name 1700 { 1701 buf.writeByte(i + '0'); 1702 return true; 1703 } 1704 } 1705 return false; 1706 } 1707 1708 void saveIdent(const(char)* name) 1709 { 1710 foreach (i; 0 .. VC_SAVED_IDENT_CNT) 1711 { 1712 if (!saved_idents[i]) // no saved same name 1713 { 1714 saved_idents[i] = name; 1715 break; 1716 } 1717 if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name 1718 { 1719 return; 1720 } 1721 } 1722 } 1723 1724 void mangleIdent(Dsymbol sym, bool dont_use_back_reference = false) 1725 { 1726 // <qualified name> ::= <sub-name list> @ 1727 // <sub-name list> ::= <sub-name> <name parts> 1728 // ::= <sub-name> 1729 // <sub-name> ::= <identifier> @ 1730 // ::= ?$ <identifier> @ <template args> @ 1731 // :: <back reference> 1732 // <back reference> ::= 0-9 1733 // <template args> ::= <template arg> <template args> 1734 // ::= <template arg> 1735 // <template arg> ::= <type> 1736 // ::= $0<encoded integral number> 1737 //printf("mangleIdent('%s')\n", sym.toChars()); 1738 Dsymbol p = sym; 1739 if (p.toParent() && p.toParent().isTemplateInstance()) 1740 { 1741 p = p.toParent(); 1742 } 1743 while (p && !p.isModule()) 1744 { 1745 mangleName(p, dont_use_back_reference); 1746 p = p.toParent(); 1747 if (p.toParent() && p.toParent().isTemplateInstance()) 1748 { 1749 p = p.toParent(); 1750 } 1751 } 1752 if (!dont_use_back_reference) 1753 buf.writeByte('@'); 1754 } 1755 1756 void mangleNumber(dinteger_t num) 1757 { 1758 if (!num) // 0 encoded as "A@" 1759 { 1760 buf.writeByte('A'); 1761 buf.writeByte('@'); 1762 return; 1763 } 1764 if (num <= 10) // 5 encoded as "4" 1765 { 1766 buf.writeByte(cast(char)(num - 1 + '0')); 1767 return; 1768 } 1769 char[17] buff; 1770 buff[16] = 0; 1771 size_t i = 16; 1772 while (num) 1773 { 1774 --i; 1775 buff[i] = num % 16 + 'A'; 1776 num /= 16; 1777 } 1778 buf.writestring(&buff[i]); 1779 buf.writeByte('@'); 1780 } 1781 1782 bool checkTypeSaved(Type type) 1783 { 1784 if (flags & IS_NOT_TOP_TYPE) 1785 return false; 1786 if (flags & MANGLE_RETURN_TYPE) 1787 return false; 1788 for (uint i = 0; i < VC_SAVED_TYPE_CNT; i++) 1789 { 1790 if (!saved_types[i]) // no saved same type 1791 { 1792 saved_types[i] = type; 1793 return false; 1794 } 1795 if (saved_types[i].equals(type)) // ok, we've found same type. use index instead of type 1796 { 1797 buf.writeByte(i + '0'); 1798 flags &= ~IS_NOT_TOP_TYPE; 1799 flags &= ~IGNORE_CONST; 1800 return true; 1801 } 1802 } 1803 return false; 1804 } 1805 1806 void mangleModifier(Type type) 1807 { 1808 if (flags & IGNORE_CONST) 1809 return; 1810 if (type.isImmutable() || type.isShared()) 1811 { 1812 visit(type); 1813 return; 1814 } 1815 if (type.isConst()) 1816 { 1817 if (flags & IS_NOT_TOP_TYPE) 1818 buf.writeByte('B'); // const 1819 else if ((flags & IS_DMC) && type.ty != Tpointer) 1820 buf.writestring("_O"); 1821 } 1822 else if (flags & IS_NOT_TOP_TYPE) 1823 buf.writeByte('A'); // mutable 1824 } 1825 1826 void mangleArray(TypeSArray type) 1827 { 1828 mangleModifier(type); 1829 size_t i = 0; 1830 Type cur = type; 1831 while (cur && cur.ty == Tsarray) 1832 { 1833 i++; 1834 cur = cur.nextOf(); 1835 } 1836 buf.writeByte('Y'); 1837 mangleNumber(i); // count of dimensions 1838 cur = type; 1839 while (cur && cur.ty == Tsarray) // sizes of dimensions 1840 { 1841 TypeSArray sa = cast(TypeSArray)cur; 1842 mangleNumber(sa.dim ? sa.dim.toInteger() : 0); 1843 cur = cur.nextOf(); 1844 } 1845 flags |= IGNORE_CONST; 1846 cur.accept(this); 1847 } 1848 1849 const(char)* mangleFunctionType(TypeFunction type, bool needthis = false, bool noreturn = false) 1850 { 1851 scope VisualCPPMangler tmp = new VisualCPPMangler(this); 1852 // Calling convention 1853 if (global.params.is64bit) // always Microsoft x64 calling convention 1854 { 1855 tmp.buf.writeByte('A'); 1856 } 1857 else 1858 { 1859 switch (type.linkage) 1860 { 1861 case LINKc: 1862 tmp.buf.writeByte('A'); 1863 break; 1864 case LINKcpp: 1865 if (needthis && type.varargs != 1) 1866 tmp.buf.writeByte('E'); // thiscall 1867 else 1868 tmp.buf.writeByte('A'); // cdecl 1869 break; 1870 case LINKwindows: 1871 tmp.buf.writeByte('G'); // stdcall 1872 break; 1873 case LINKpascal: 1874 tmp.buf.writeByte('C'); 1875 break; 1876 default: 1877 tmp.visit(cast(Type)type); 1878 break; 1879 } 1880 } 1881 tmp.flags &= ~IS_NOT_TOP_TYPE; 1882 if (noreturn) 1883 { 1884 tmp.buf.writeByte('@'); 1885 } 1886 else 1887 { 1888 Type rettype = type.next; 1889 if (type.isref) 1890 rettype = rettype.referenceTo(); 1891 flags &= ~IGNORE_CONST; 1892 if (rettype.ty == Tstruct || rettype.ty == Tenum) 1893 { 1894 const id = rettype.toDsymbol(null).ident; 1895 if (id != Id.__c_long_double && id != Id.__c_long && id != Id.__c_ulong) 1896 { 1897 tmp.buf.writeByte('?'); 1898 tmp.buf.writeByte('A'); 1899 } 1900 } 1901 tmp.flags |= MANGLE_RETURN_TYPE; 1902 rettype.accept(tmp); 1903 tmp.flags &= ~MANGLE_RETURN_TYPE; 1904 } 1905 if (!type.parameters || !type.parameters.dim) 1906 { 1907 if (type.varargs == 1) 1908 tmp.buf.writeByte('Z'); 1909 else 1910 tmp.buf.writeByte('X'); 1911 } 1912 else 1913 { 1914 int mangleParameterDg(size_t n, Parameter p) 1915 { 1916 Type t = p.type; 1917 if (p.storageClass & (STCout | STCref)) 1918 { 1919 t = t.referenceTo(); 1920 } 1921 else if (p.storageClass & STClazy) 1922 { 1923 // Mangle as delegate 1924 Type td = new TypeFunction(null, t, 0, LINKd); 1925 td = new TypeDelegate(td); 1926 t = t.merge(); 1927 } 1928 if (t.ty == Tsarray) 1929 { 1930 t.error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function."); 1931 t.error(Loc(), "Use pointer instead."); 1932 assert(0); 1933 } 1934 tmp.flags &= ~IS_NOT_TOP_TYPE; 1935 tmp.flags &= ~IGNORE_CONST; 1936 t.accept(tmp); 1937 return 0; 1938 } 1939 1940 Parameter._foreach(type.parameters, &mangleParameterDg); 1941 if (type.varargs == 1) 1942 { 1943 tmp.buf.writeByte('Z'); 1944 } 1945 else 1946 { 1947 tmp.buf.writeByte('@'); 1948 } 1949 } 1950 tmp.buf.writeByte('Z'); 1951 const(char)* ret = tmp.buf.extractString(); 1952 memcpy(&saved_idents, &tmp.saved_idents, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); 1953 memcpy(&saved_types, &tmp.saved_types, Type.sizeof * VC_SAVED_TYPE_CNT); 1954 return ret; 1955 } 1956 } 1957 1958 extern (C++) const(char)* toCppMangle(Dsymbol s) 1959 { 1960 scope VisualCPPMangler v = new VisualCPPMangler(!global.params.mscoff); 1961 return v.mangleOf(s); 1962 } 1963 1964 extern (C++) const(char)* cppTypeInfoMangle(Dsymbol s) 1965 { 1966 //printf("cppTypeInfoMangle(%s)\n", s.toChars()); 1967 assert(0); 1968 } 1969 } 1970 else 1971 { 1972 static assert(0, "fix this"); 1973 }