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