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