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