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