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 _dmangle.d)
8  */
9 
10 module ddmd.dmangle;
11 
12 import core.stdc.ctype;
13 import core.stdc.stdio;
14 import core.stdc..string;
15 
16 import ddmd.aggregate;
17 import ddmd.arraytypes;
18 import ddmd.cppmangle;
19 import ddmd.dclass;
20 import ddmd.declaration;
21 import ddmd.dmodule;
22 import ddmd.dsymbol;
23 import ddmd.dtemplate;
24 import ddmd.expression;
25 import ddmd.func;
26 import ddmd.globals;
27 import ddmd.id;
28 import ddmd.mtype;
29 import ddmd.root.ctfloat;
30 import ddmd.root.outbuffer;
31 import ddmd.utf;
32 import ddmd.visitor;
33 
34 private immutable char[TMAX] mangleChar =
35 [
36     Tchar        : 'a',
37     Tbool        : 'b',
38     Tcomplex80   : 'c',
39     Tfloat64     : 'd',
40     Tfloat80     : 'e',
41     Tfloat32     : 'f',
42     Tint8        : 'g',
43     Tuns8        : 'h',
44     Tint32       : 'i',
45     Timaginary80 : 'j',
46     Tuns32       : 'k',
47     Tint64       : 'l',
48     Tuns64       : 'm',
49     Tnone        : 'n',
50     Tnull        : 'n', // yes, same as TypeNone
51     Timaginary32 : 'o',
52     Timaginary64 : 'p',
53     Tcomplex32   : 'q',
54     Tcomplex64   : 'r',
55     Tint16       : 's',
56     Tuns16       : 't',
57     Twchar       : 'u',
58     Tvoid        : 'v',
59     Tdchar       : 'w',
60     //              x   // const
61     //              y   // immutable
62     Tint128      : 'z', // zi
63     Tuns128      : 'z', // zk
64 
65     Tarray       : 'A',
66     Ttuple       : 'B',
67     Tclass       : 'C',
68     Tdelegate    : 'D',
69     Tenum        : 'E',
70     Tfunction    : 'F', // D function
71     Tsarray      : 'G',
72     Taarray      : 'H',
73     Tident       : 'I',
74     //              J   // out
75     //              K   // ref
76     //              L   // lazy
77     //              M   // has this, or scope
78     //              N   // Nh:vector Ng:wild
79     //              O   // shared
80     Tpointer     : 'P',
81     //              Q
82     Treference   : 'R',
83     Tstruct      : 'S',
84     //              T   // Ttypedef
85     //              U   // C function
86     //              V   // Pascal function
87     //              W   // Windows function
88     //              X   // variadic T t...)
89     //              Y   // variadic T t,...)
90     //              Z   // not variadic, end of parameters
91 
92     // '@' shouldn't appear anywhere in the deco'd names
93     Tinstance    : '@',
94     Terror       : '@',
95     Ttypeof      : '@',
96     Tslice       : '@',
97     Treturn      : '@',
98     Tvector      : '@',
99 ];
100 
101 unittest
102 {
103     foreach (i, mangle; mangleChar)
104     {
105         if (mangle == char.init)
106         {
107             fprintf(stderr, "ty = %u\n", cast(uint)i);
108             assert(0);
109         }
110     }
111 }
112 
113 /***********************
114  * Mangle basic type ty to buf.
115  */
116 
117 private void tyToDecoBuffer(OutBuffer* buf, int ty)
118 {
119     const c = mangleChar[ty];
120     buf.writeByte(c);
121     if (c == 'z')
122         buf.writeByte(ty == Tint128 ? 'i' : 'k');
123 }
124 
125 /*********************************
126  * Mangling for mod.
127  */
128 private void MODtoDecoBuffer(OutBuffer* buf, MOD mod)
129 {
130     switch (mod)
131     {
132     case 0:
133         break;
134     case MODconst:
135         buf.writeByte('x');
136         break;
137     case MODimmutable:
138         buf.writeByte('y');
139         break;
140     case MODshared:
141         buf.writeByte('O');
142         break;
143     case MODshared | MODconst:
144         buf.writestring("Ox");
145         break;
146     case MODwild:
147         buf.writestring("Ng");
148         break;
149     case MODwildconst:
150         buf.writestring("Ngx");
151         break;
152     case MODshared | MODwild:
153         buf.writestring("ONg");
154         break;
155     case MODshared | MODwildconst:
156         buf.writestring("ONgx");
157         break;
158     default:
159         assert(0);
160     }
161 }
162 
163 extern (C++) final class Mangler : Visitor
164 {
165     alias visit = super.visit;
166 public:
167     OutBuffer* buf;
168 
169     extern (D) this(OutBuffer* buf)
170     {
171         this.buf = buf;
172     }
173 
174     ////////////////////////////////////////////////////////////////////////////
175     /**************************************************
176      * Type mangling
177      */
178     void visitWithMask(Type t, ubyte modMask)
179     {
180         if (t.deco && modMask == 0)
181         {
182             buf.writestring(t.deco);    // don't need to recreate it
183             return;
184         }
185         if (modMask != t.mod)
186         {
187             MODtoDecoBuffer(buf, t.mod);
188         }
189         t.accept(this);
190     }
191 
192     override void visit(Type t)
193     {
194         tyToDecoBuffer(buf, t.ty);
195     }
196 
197     override void visit(TypeNext t)
198     {
199         visit(cast(Type)t);
200         visitWithMask(t.next, t.mod);
201     }
202 
203     override void visit(TypeVector t)
204     {
205         buf.writestring("Nh");
206         visitWithMask(t.basetype, t.mod);
207     }
208 
209     override void visit(TypeSArray t)
210     {
211         visit(cast(Type)t);
212         if (t.dim)
213             buf.printf("%u", cast(uint)t.dim.toInteger());
214         if (t.next)
215             visitWithMask(t.next, t.mod);
216     }
217 
218     override void visit(TypeDArray t)
219     {
220         visit(cast(Type)t);
221         if (t.next)
222             visitWithMask(t.next, t.mod);
223     }
224 
225     override void visit(TypeAArray t)
226     {
227         visit(cast(Type)t);
228         visitWithMask(t.index, 0);
229         visitWithMask(t.next, t.mod);
230     }
231 
232     override void visit(TypeFunction t)
233     {
234         //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
235         //static int nest; if (++nest == 50) *(char*)0=0;
236         mangleFuncType(t, t, t.mod, t.next);
237     }
238 
239     void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret)
240     {
241         //printf("mangleFuncType() %s\n", t.toChars());
242         if (t.inuse)
243         {
244             t.inuse = 2; // flag error to caller
245             return;
246         }
247         t.inuse++;
248         if (modMask != t.mod)
249             MODtoDecoBuffer(buf, t.mod);
250         ubyte mc;
251         switch (t.linkage)
252         {
253         case LINKd:
254             mc = 'F';
255             break;
256         case LINKc:
257             mc = 'U';
258             break;
259         case LINKwindows:
260             mc = 'W';
261             break;
262         case LINKpascal:
263             mc = 'V';
264             break;
265         case LINKcpp:
266             mc = 'R';
267             break;
268         case LINKobjc:
269             mc = 'Y';
270             break;
271         default:
272             assert(0);
273         }
274         buf.writeByte(mc);
275         if (ta.purity || ta.isnothrow || ta.isnogc || ta.isproperty || ta.isref || ta.trust || ta.isreturn || ta.isscope)
276         {
277             if (ta.purity)
278                 buf.writestring("Na");
279             if (ta.isnothrow)
280                 buf.writestring("Nb");
281             if (ta.isref)
282                 buf.writestring("Nc");
283             if (ta.isproperty)
284                 buf.writestring("Nd");
285             if (ta.isnogc)
286                 buf.writestring("Ni");
287             if (ta.isreturn)
288                 buf.writestring("Nj");
289             if (ta.isscope && !ta.isreturn)
290                 buf.writestring("M");
291             switch (ta.trust)
292             {
293             case TRUSTtrusted:
294                 buf.writestring("Ne");
295                 break;
296             case TRUSTsafe:
297                 buf.writestring("Nf");
298                 break;
299             default:
300                 break;
301             }
302         }
303         // Write argument types
304         paramsToDecoBuffer(t.parameters);
305         //if (buf.data[buf.offset - 1] == '@') assert(0);
306         buf.writeByte('Z' - t.varargs); // mark end of arg list
307         if (tret !is null)
308             visitWithMask(tret, 0);
309         t.inuse--;
310     }
311 
312     override void visit(TypeIdentifier t)
313     {
314         visit(cast(Type)t);
315         const(char)* name = t.ident.toChars();
316         size_t len = strlen(name);
317         buf.printf("%u%s", cast(uint)len, name);
318     }
319 
320     override void visit(TypeEnum t)
321     {
322         visit(cast(Type)t);
323         t.sym.accept(this);
324     }
325 
326     override void visit(TypeStruct t)
327     {
328         //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
329         visit(cast(Type)t);
330         t.sym.accept(this);
331     }
332 
333     override void visit(TypeClass t)
334     {
335         //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
336         visit(cast(Type)t);
337         t.sym.accept(this);
338     }
339 
340     override void visit(TypeTuple t)
341     {
342         //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
343         visit(cast(Type)t);
344         OutBuffer buf2;
345         buf2.reserve(32);
346         scope Mangler v = new Mangler(&buf2);
347         v.paramsToDecoBuffer(t.arguments);
348         auto s = buf2.peekSlice();
349         int len = cast(int)s.length;
350         buf.printf("%d%.*s", len, len, s.ptr);
351     }
352 
353     override void visit(TypeNull t)
354     {
355         visit(cast(Type)t);
356     }
357 
358     ////////////////////////////////////////////////////////////////////////////
359     void mangleDecl(Declaration sthis)
360     {
361         mangleParent(sthis);
362         assert(sthis.ident);
363         const(char)* id = sthis.ident.toChars();
364         toBuffer(id, sthis);
365         if (FuncDeclaration fd = sthis.isFuncDeclaration())
366         {
367             mangleFunc(fd, false);
368         }
369         else if (sthis.type.deco)
370         {
371             buf.writestring(sthis.type.deco);
372         }
373         else
374             assert(0);
375     }
376 
377     void mangleParent(Dsymbol s)
378     {
379         Dsymbol p;
380         if (TemplateInstance ti = s.isTemplateInstance())
381             p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent;
382         else
383             p = s.parent;
384         if (p)
385         {
386             mangleParent(p);
387             if (p.getIdent())
388             {
389                 const(char)* id = p.ident.toChars();
390                 toBuffer(id, s);
391                 if (FuncDeclaration f = p.isFuncDeclaration())
392                     mangleFunc(f, true);
393             }
394             else
395                 buf.writeByte('0');
396         }
397     }
398 
399     void mangleFunc(FuncDeclaration fd, bool inParent)
400     {
401         //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
402         //printf("fd.type = %s\n", fd.type.toChars());
403         if (fd.needThis() || fd.isNested())
404             buf.writeByte('M');
405         if (inParent)
406         {
407             TypeFunction tf = cast(TypeFunction)fd.type;
408             TypeFunction tfo = cast(TypeFunction)fd.originalType;
409             mangleFuncType(tf, tfo, 0, null);
410         }
411         else if (fd.type.deco)
412         {
413             buf.writestring(fd.type.deco);
414         }
415         else
416         {
417             printf("[%s] %s %s\n", fd.loc.toChars(), fd.toChars(), fd.type.toChars());
418             assert(0); // don't mangle function until semantic3 done.
419         }
420     }
421 
422     /************************************************************
423      * Write length prefixed string to buf.
424      */
425     void toBuffer(const(char)* id, Dsymbol s)
426     {
427         size_t len = strlen(id);
428         if (len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
429             s.error("excessive length %llu for symbol, possible recursive expansion?", len);
430         else
431         {
432             buf.printf("%u", cast(uint)len);
433             buf.write(id, len);
434         }
435     }
436 
437     override void visit(Declaration d)
438     {
439         //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
440         //        d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
441         if (!d.parent || d.parent.isModule() || d.linkage == LINKcpp) // if at global scope
442         {
443             switch (d.linkage)
444             {
445             case LINKd:
446                 break;
447             case LINKc:
448             case LINKwindows:
449             case LINKpascal:
450             case LINKobjc:
451                 buf.writestring(d.ident.toChars());
452                 return;
453             case LINKcpp:
454                 buf.writestring(toCppMangle(d));
455                 return;
456             case LINKdefault:
457                 d.error("forward declaration");
458                 buf.writestring(d.ident.toChars());
459                 return;
460             default:
461                 fprintf(stderr, "'%s', linkage = %d\n", d.toChars(), d.linkage);
462                 assert(0);
463             }
464         }
465         buf.writestring("_D");
466         mangleDecl(d);
467         debug
468         {
469             const slice = buf.peekSlice();
470             assert(slice.length);
471             foreach (const char c; slice)
472             {
473                 assert(c == '_' || c == '@' || c == '?' || c == '$' || isalnum(c) || c & 0x80);
474             }
475         }
476     }
477 
478     /******************************************************************************
479      * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
480      * If and only if there is no overloads, mangle() could return
481      * exact mangled name.
482      *
483      *      module test;
484      *      void foo(long) {}           // _D4test3fooFlZv
485      *      void foo(string) {}         // _D4test3fooFAyaZv
486      *
487      *      // from FuncDeclaration.mangle().
488      *      pragma(msg, foo.mangleof);  // prints unexact mangled name "4test3foo"
489      *                                  // by calling Dsymbol.mangle()
490      *
491      *      // from FuncAliasDeclaration.mangle()
492      *      pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof);  // "_D4test3fooFlZv"
493      *      pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof);  // "_D4test3fooFAyaZv"
494      *
495      * If a function has no overloads, .mangleof property still returns exact mangled name.
496      *
497      *      void bar() {}
498      *      pragma(msg, bar.mangleof);  // still prints "_D4test3barFZv"
499      *                                  // by calling FuncDeclaration.mangleExact().
500      */
501     override void visit(FuncDeclaration fd)
502     {
503         if (fd.isUnique())
504             mangleExact(fd);
505         else
506             visit(cast(Dsymbol)fd);
507     }
508 
509     // ditto
510     override void visit(FuncAliasDeclaration fd)
511     {
512         FuncDeclaration f = fd.toAliasFunc();
513         FuncAliasDeclaration fa = f.isFuncAliasDeclaration();
514         if (!fd.hasOverloads && !fa)
515         {
516             mangleExact(f);
517             return;
518         }
519         if (fa)
520         {
521             fa.accept(this);
522             return;
523         }
524         visit(cast(Dsymbol)fd);
525     }
526 
527     override void visit(OverDeclaration od)
528     {
529         if (od.overnext)
530         {
531             visit(cast(Dsymbol)od);
532             return;
533         }
534         if (FuncDeclaration fd = od.aliassym.isFuncDeclaration())
535         {
536             if (!od.hasOverloads || fd.isUnique())
537             {
538                 mangleExact(fd);
539                 return;
540             }
541         }
542         if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration())
543         {
544             if (!od.hasOverloads || td.overnext is null)
545             {
546                 td.accept(this);
547                 return;
548             }
549         }
550         visit(cast(Dsymbol)od);
551     }
552 
553     void mangleExact(FuncDeclaration fd)
554     {
555         assert(!fd.isFuncAliasDeclaration());
556         if (fd.mangleOverride)
557         {
558             buf.writestring(fd.mangleOverride);
559             return;
560         }
561         if (fd.isMain())
562         {
563             buf.writestring("_Dmain");
564             return;
565         }
566         if (fd.isWinMain() || fd.isDllMain() || fd.ident == Id.tls_get_addr)
567         {
568             buf.writestring(fd.ident.toChars());
569             return;
570         }
571         visit(cast(Declaration)fd);
572     }
573 
574     override void visit(VarDeclaration vd)
575     {
576         if (vd.mangleOverride)
577         {
578             buf.writestring(vd.mangleOverride);
579             return;
580         }
581         visit(cast(Declaration)vd);
582     }
583 
584     override void visit(AggregateDeclaration ad)
585     {
586         ClassDeclaration cd = ad.isClassDeclaration();
587         Dsymbol parentsave = ad.parent;
588         if (cd)
589         {
590             /* These are reserved to the compiler, so keep simple
591              * names for them.
592              */
593             if (cd.ident == Id.Exception && cd.parent.ident == Id.object || cd.ident == Id.TypeInfo || cd.ident == Id.TypeInfo_Struct || cd.ident == Id.TypeInfo_Class || cd.ident == Id.TypeInfo_Tuple || cd == ClassDeclaration.object || cd == Type.typeinfoclass || cd == Module.moduleinfo || strncmp(cd.ident.toChars(), "TypeInfo_", 9) == 0)
594             {
595                 // Don't mangle parent
596                 ad.parent = null;
597             }
598         }
599         visit(cast(Dsymbol)ad);
600         ad.parent = parentsave;
601     }
602 
603     override void visit(TemplateInstance ti)
604     {
605         version (none)
606         {
607             printf("TemplateInstance.mangle() %p %s", ti, ti.toChars());
608             if (ti.parent)
609                 printf("  parent = %s %s", ti.parent.kind(), ti.parent.toChars());
610             printf("\n");
611         }
612         if (!ti.tempdecl)
613             ti.error("is not defined");
614         else
615             mangleParent(ti);
616         ti.getIdent();
617         const(char)* id = ti.ident ? ti.ident.toChars() : ti.toChars();
618         toBuffer(id, ti);
619         //printf("TemplateInstance.mangle() %s = %s\n", ti.toChars(), ti.id);
620     }
621 
622     override void visit(Dsymbol s)
623     {
624         version (none)
625         {
626             printf("Dsymbol.mangle() '%s'", s.toChars());
627             if (s.parent)
628                 printf("  parent = %s %s", s.parent.kind(), s.parent.toChars());
629             printf("\n");
630         }
631         mangleParent(s);
632         auto id = s.ident ? s.ident.toChars() : s.toChars();
633         toBuffer(id, s);
634         //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
635     }
636 
637     ////////////////////////////////////////////////////////////////////////////
638     override void visit(Expression e)
639     {
640         e.error("expression %s is not a valid template value argument", e.toChars());
641     }
642 
643     override void visit(IntegerExp e)
644     {
645         if (cast(sinteger_t)e.value < 0)
646             buf.printf("N%lld", -e.value);
647         else
648             buf.printf("i%lld", e.value);
649     }
650 
651     override void visit(RealExp e)
652     {
653         buf.writeByte('e');
654         realToMangleBuffer(e.value);
655     }
656 
657     void realToMangleBuffer(real_t value)
658     {
659         /* Rely on %A to get portable mangling.
660          * Must munge result to get only identifier characters.
661          *
662          * Possible values from %A  => mangled result
663          * NAN                      => NAN
664          * -INF                     => NINF
665          * INF                      => INF
666          * -0X1.1BC18BA997B95P+79   => N11BC18BA997B95P79
667          * 0X1.9P+2                 => 19P2
668          */
669         if (CTFloat.isNaN(value))
670             buf.writestring("NAN"); // no -NAN bugs
671         else if (CTFloat.isInfinity(value))
672             buf.writestring(value < CTFloat.zero ? "NINF" : "INF");
673         else
674         {
675             enum BUFFER_LEN = 36;
676             char[BUFFER_LEN] buffer;
677             const n = CTFloat.sprint(buffer.ptr, 'A', value);
678             assert(n < BUFFER_LEN);
679             for (int i = 0; i < n; i++)
680             {
681                 char c = buffer[i];
682                 switch (c)
683                 {
684                 case '-':
685                     buf.writeByte('N');
686                     break;
687                 case '+':
688                 case 'X':
689                 case '.':
690                     break;
691                 case '0':
692                     if (i < 2)
693                         break; // skip leading 0X
694                     goto default;
695                 default:
696                     buf.writeByte(c);
697                     break;
698                 }
699             }
700         }
701     }
702 
703     override void visit(ComplexExp e)
704     {
705         buf.writeByte('c');
706         realToMangleBuffer(e.toReal());
707         buf.writeByte('c'); // separate the two
708         realToMangleBuffer(e.toImaginary());
709     }
710 
711     override void visit(NullExp e)
712     {
713         buf.writeByte('n');
714     }
715 
716     override void visit(StringExp e)
717     {
718         char m;
719         OutBuffer tmp;
720         const(char)[] q;
721         /* Write string in UTF-8 format
722          */
723         switch (e.sz)
724         {
725         case 1:
726             m = 'a';
727             q = e..string[0 .. e.len];
728             break;
729         case 2:
730             m = 'w';
731             for (size_t u = 0; u < e.len;)
732             {
733                 dchar c;
734                 const p = utf_decodeWchar(e.wstring, e.len, u, c);
735                 if (p)
736                     e.error("%s", p);
737                 else
738                     tmp.writeUTF8(c);
739             }
740             q = tmp.peekSlice();
741             break;
742         case 4:
743             m = 'd';
744             for (size_t u = 0; u < e.len; u++)
745             {
746                 uint c = (cast(uint*)e..string)[u];
747                 if (!utf_isValidDchar(c))
748                     e.error("invalid UCS-32 char \\U%08x", c);
749                 else
750                     tmp.writeUTF8(c);
751             }
752             q = tmp.peekSlice();
753             break;
754         default:
755             assert(0);
756         }
757         buf.reserve(1 + 11 + 2 * q.length);
758         buf.writeByte(m);
759         buf.printf("%d_", cast(int)q.length); // nbytes <= 11
760         size_t qi = 0;
761         for (char* p = cast(char*)buf.data + buf.offset, pend = p + 2 * q.length; p < pend; p += 2, ++qi)
762         {
763             char hi = (q[qi] >> 4) & 0xF;
764             p[0] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a');
765             char lo = q[qi] & 0xF;
766             p[1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a');
767         }
768         buf.offset += 2 * q.length;
769     }
770 
771     override void visit(ArrayLiteralExp e)
772     {
773         size_t dim = e.elements ? e.elements.dim : 0;
774         buf.printf("A%u", cast(uint)dim);
775         for (size_t i = 0; i < dim; i++)
776         {
777             e.getElement(i).accept(this);
778         }
779     }
780 
781     override void visit(AssocArrayLiteralExp e)
782     {
783         size_t dim = e.keys.dim;
784         buf.printf("A%u", cast(uint)dim);
785         for (size_t i = 0; i < dim; i++)
786         {
787             (*e.keys)[i].accept(this);
788             (*e.values)[i].accept(this);
789         }
790     }
791 
792     override void visit(StructLiteralExp e)
793     {
794         size_t dim = e.elements ? e.elements.dim : 0;
795         buf.printf("S%u", cast(uint)dim);
796         for (size_t i = 0; i < dim; i++)
797         {
798             Expression ex = (*e.elements)[i];
799             if (ex)
800                 ex.accept(this);
801             else
802                 buf.writeByte('v'); // 'v' for void
803         }
804     }
805 
806     ////////////////////////////////////////////////////////////////////////////
807     void paramsToDecoBuffer(Parameters* parameters)
808     {
809         //printf("Parameter.paramsToDecoBuffer()\n");
810 
811         int paramsToDecoBufferDg(size_t n, Parameter p)
812         {
813             p.accept(this);
814             return 0;
815         }
816 
817         Parameter._foreach(parameters, &paramsToDecoBufferDg);
818     }
819 
820     override void visit(Parameter p)
821     {
822         if (p.storageClass & STCscope)
823             buf.writeByte('M');
824         // 'return inout ref' is the same as 'inout ref'
825         if ((p.storageClass & (STCreturn | STCwild)) == STCreturn)
826             buf.writestring("Nk");
827         switch (p.storageClass & (STCin | STCout | STCref | STClazy))
828         {
829         case 0:
830         case STCin:
831             break;
832         case STCout:
833             buf.writeByte('J');
834             break;
835         case STCref:
836             buf.writeByte('K');
837             break;
838         case STClazy:
839             buf.writeByte('L');
840             break;
841         default:
842             debug
843             {
844                 printf("storageClass = x%llx\n", p.storageClass & (STCin | STCout | STCref | STClazy));
845             }
846             assert(0);
847         }
848         visitWithMask(p.type, 0);
849     }
850 }
851 
852 
853 /******************************************************************************
854  * Returns exact mangled name of function.
855  */
856 extern (C++) const(char)* mangleExact(FuncDeclaration fd)
857 {
858     if (!fd.mangleString)
859     {
860         OutBuffer buf;
861         scope Mangler v = new Mangler(&buf);
862         v.mangleExact(fd);
863         fd.mangleString = buf.extractString();
864     }
865     return fd.mangleString;
866 }
867 
868 extern (C++) void mangleToBuffer(Type t, OutBuffer* buf)
869 {
870     if (t.deco)
871         buf.writestring(t.deco);
872     else
873     {
874         scope Mangler v = new Mangler(buf);
875         v.visitWithMask(t, 0);
876     }
877 }
878 
879 extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf)
880 {
881     scope Mangler v = new Mangler(buf);
882     e.accept(v);
883 }
884 
885 extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf)
886 {
887     scope Mangler v = new Mangler(buf);
888     s.accept(v);
889 }
890