1 /**
2  * Does name mangling for `extern(D)` symbols.
3  *
4  * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling)
5  *
6  * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
7  * Authors: Walter Bright, http://www.digitalmars.com
8  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d)
10  * Documentation:  https://dlang.org/phobos/dmd_dmangle.html
11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmangle.d
12  * References:  https://dlang.org/blog/2017/12/20/ds-newfangled-name-mangling/
13  */
14 
15 module dmd.dmangle;
16 
17 import core.stdc.ctype;
18 import core.stdc.stdio;
19 import core.stdc.string;
20 
21 import dmd.aggregate;
22 import dmd.arraytypes;
23 import dmd.dclass;
24 import dmd.declaration;
25 import dmd.dmodule;
26 import dmd.dsymbol;
27 import dmd.dtemplate;
28 import dmd.expression;
29 import dmd.func;
30 import dmd.globals;
31 import dmd.id;
32 import dmd.identifier;
33 import dmd.mtype;
34 import dmd.root.ctfloat;
35 import dmd.root.outbuffer;
36 import dmd.root.aav;
37 import dmd.root.string;
38 import dmd.target;
39 import dmd.tokens;
40 import dmd.utf;
41 import dmd.visitor;
42 
43 private immutable char[TMAX] mangleChar =
44 [
45     Tchar        : 'a',
46     Tbool        : 'b',
47     Tcomplex80   : 'c',
48     Tfloat64     : 'd',
49     Tfloat80     : 'e',
50     Tfloat32     : 'f',
51     Tint8        : 'g',
52     Tuns8        : 'h',
53     Tint32       : 'i',
54     Timaginary80 : 'j',
55     Tuns32       : 'k',
56     Tint64       : 'l',
57     Tuns64       : 'm',
58     Tnone        : 'n',
59     Tnull        : 'n', // yes, same as TypeNone
60     Timaginary32 : 'o',
61     Timaginary64 : 'p',
62     Tcomplex32   : 'q',
63     Tcomplex64   : 'r',
64     Tint16       : 's',
65     Tuns16       : 't',
66     Twchar       : 'u',
67     Tvoid        : 'v',
68     Tdchar       : 'w',
69     //              x   // const
70     //              y   // immutable
71     Tint128      : 'z', // zi
72     Tuns128      : 'z', // zk
73 
74     Tarray       : 'A',
75     Ttuple       : 'B',
76     Tclass       : 'C',
77     Tdelegate    : 'D',
78     Tenum        : 'E',
79     Tfunction    : 'F', // D function
80     Tsarray      : 'G',
81     Taarray      : 'H',
82     Tident       : 'I',
83     //              J   // out
84     //              K   // ref
85     //              L   // lazy
86     //              M   // has this, or scope
87     //              N   // Nh:vector Ng:wild
88     //              O   // shared
89     Tpointer     : 'P',
90     //              Q   // Type/symbol/identifier backward reference
91     Treference   : 'R',
92     Tstruct      : 'S',
93     //              T   // Ttypedef
94     //              U   // C function
95     //              V   // Pascal function
96     //              W   // Windows function
97     //              X   // variadic T t...)
98     //              Y   // variadic T t,...)
99     //              Z   // not variadic, end of parameters
100 
101     // '@' shouldn't appear anywhere in the deco'd names
102     Tinstance    : '@',
103     Terror       : '@',
104     Ttypeof      : '@',
105     Tslice       : '@',
106     Treturn      : '@',
107     Tvector      : '@',
108     Ttraits      : '@',
109     Tmixin       : '@',
110 ];
111 
112 unittest
113 {
114     foreach (i, mangle; mangleChar)
115     {
116         if (mangle == char.init)
117         {
118             fprintf(stderr, "ty = %u\n", cast(uint)i);
119             assert(0);
120         }
121     }
122 }
123 
124 /***********************
125  * Mangle basic type ty to buf.
126  */
127 
128 private void tyToDecoBuffer(OutBuffer* buf, int ty)
129 {
130     const c = mangleChar[ty];
131     buf.writeByte(c);
132     if (c == 'z')
133         buf.writeByte(ty == Tint128 ? 'i' : 'k');
134 }
135 
136 /*********************************
137  * Mangling for mod.
138  */
139 private void MODtoDecoBuffer(OutBuffer* buf, MOD mod)
140 {
141     switch (mod)
142     {
143     case 0:
144         break;
145     case MODFlags.const_:
146         buf.writeByte('x');
147         break;
148     case MODFlags.immutable_:
149         buf.writeByte('y');
150         break;
151     case MODFlags.shared_:
152         buf.writeByte('O');
153         break;
154     case MODFlags.shared_ | MODFlags.const_:
155         buf.writestring("Ox");
156         break;
157     case MODFlags.wild:
158         buf.writestring("Ng");
159         break;
160     case MODFlags.wildconst:
161         buf.writestring("Ngx");
162         break;
163     case MODFlags.shared_ | MODFlags.wild:
164         buf.writestring("ONg");
165         break;
166     case MODFlags.shared_ | MODFlags.wildconst:
167         buf.writestring("ONgx");
168         break;
169     default:
170         assert(0);
171     }
172 }
173 
174 private extern (C++) final class Mangler : Visitor
175 {
176     alias visit = Visitor.visit;
177 public:
178     static assert(Key.sizeof == size_t.sizeof);
179     AssocArray!(Type, size_t) types;
180     AssocArray!(Identifier, size_t) idents;
181     OutBuffer* buf;
182 
183     extern (D) this(OutBuffer* buf)
184     {
185         this.buf = buf;
186     }
187 
188     /**
189     * writes a back reference with the relative position encoded with base 26
190     *  using upper case letters for all digits but the last digit which uses
191     *  a lower case letter.
192     * The decoder has to look up the referenced position to determine
193     *  whether the back reference is an identifer (starts with a digit)
194     *  or a type (starts with a letter).
195     *
196     * Params:
197     *  pos           = relative position to encode
198     */
199     void writeBackRef(size_t pos)
200     {
201         buf.writeByte('Q');
202         enum base = 26;
203         size_t mul = 1;
204         while (pos >= mul * base)
205             mul *= base;
206         while (mul >= base)
207         {
208             auto dig = cast(ubyte)(pos / mul);
209             buf.writeByte('A' + dig);
210             pos -= dig * mul;
211             mul /= base;
212         }
213         buf.writeByte('a' + cast(ubyte)pos);
214     }
215 
216     /**
217     * Back references a non-basic type
218     *
219     * The encoded mangling is
220     *       'Q' <relative position of first occurrence of type>
221     *
222     * Params:
223     *  t = the type to encode via back referencing
224     *
225     * Returns:
226     *  true if the type was found. A back reference has been encoded.
227     *  false if the type was not found. The current position is saved for later back references.
228     */
229     bool backrefType(Type t)
230     {
231         if (!t.isTypeBasic())
232         {
233             auto p = types.getLvalue(t);
234             if (*p)
235             {
236                 writeBackRef(buf.length - *p);
237                 return true;
238             }
239             *p = buf.length;
240         }
241         return false;
242     }
243 
244     /**
245     * Back references a single identifier
246     *
247     * The encoded mangling is
248     *       'Q' <relative position of first occurrence of type>
249     *
250     * Params:
251     *  id = the identifier to encode via back referencing
252     *
253     * Returns:
254     *  true if the identifier was found. A back reference has been encoded.
255     *  false if the identifier was not found. The current position is saved for later back references.
256     */
257     bool backrefIdentifier(Identifier id)
258     {
259         auto p = idents.getLvalue(id);
260         if (*p)
261         {
262             writeBackRef(buf.length - *p);
263             return true;
264         }
265         *p = buf.length;
266         return false;
267     }
268 
269     void mangleSymbol(Dsymbol s)
270     {
271         s.accept(this);
272     }
273 
274     void mangleType(Type t)
275     {
276         if (!backrefType(t))
277             t.accept(this);
278     }
279 
280     void mangleIdentifier(Identifier id, Dsymbol s)
281     {
282         if (!backrefIdentifier(id))
283             toBuffer(id.toString(), s);
284     }
285 
286     ////////////////////////////////////////////////////////////////////////////
287     /**************************************************
288      * Type mangling
289      */
290     void visitWithMask(Type t, ubyte modMask)
291     {
292         if (modMask != t.mod)
293         {
294             MODtoDecoBuffer(buf, t.mod);
295         }
296         mangleType(t);
297     }
298 
299     override void visit(Type t)
300     {
301         tyToDecoBuffer(buf, t.ty);
302     }
303 
304     override void visit(TypeNext t)
305     {
306         visit(cast(Type)t);
307         visitWithMask(t.next, t.mod);
308     }
309 
310     override void visit(TypeVector t)
311     {
312         buf.writestring("Nh");
313         visitWithMask(t.basetype, t.mod);
314     }
315 
316     override void visit(TypeSArray t)
317     {
318         visit(cast(Type)t);
319         if (t.dim)
320             buf.print(t.dim.toInteger());
321         if (t.next)
322             visitWithMask(t.next, t.mod);
323     }
324 
325     override void visit(TypeDArray t)
326     {
327         visit(cast(Type)t);
328         if (t.next)
329             visitWithMask(t.next, t.mod);
330     }
331 
332     override void visit(TypeAArray t)
333     {
334         visit(cast(Type)t);
335         visitWithMask(t.index, 0);
336         visitWithMask(t.next, t.mod);
337     }
338 
339     override void visit(TypeFunction t)
340     {
341         //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
342         //static int nest; if (++nest == 50) *(char*)0=0;
343         mangleFuncType(t, t, t.mod, t.next);
344     }
345 
346     void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret)
347     {
348         //printf("mangleFuncType() %s\n", t.toChars());
349         if (t.inuse && tret)
350         {
351             // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
352             t.inuse = 2; // flag error to caller
353             return;
354         }
355         t.inuse++;
356         if (modMask != t.mod)
357             MODtoDecoBuffer(buf, t.mod);
358 
359         char mc;
360         final switch (t.linkage)
361         {
362         case LINK.default_:
363         case LINK.system:
364         case LINK.d:
365             mc = 'F';
366             break;
367         case LINK.c:
368             mc = 'U';
369             break;
370         case LINK.windows:
371             mc = 'W';
372             break;
373         case LINK.pascal:
374             mc = 'V';
375             break;
376         case LINK.cpp:
377             mc = 'R';
378             break;
379         case LINK.objc:
380             mc = 'Y';
381             break;
382         }
383         buf.writeByte(mc);
384 
385         if (ta.purity)
386             buf.writestring("Na");
387         if (ta.isnothrow)
388             buf.writestring("Nb");
389         if (ta.isref)
390             buf.writestring("Nc");
391         if (ta.isproperty)
392             buf.writestring("Nd");
393         if (ta.isnogc)
394             buf.writestring("Ni");
395 
396         if (ta.isreturn && !ta.isreturninferred)
397             buf.writestring("Nj");
398         else if (ta.isscope && !ta.isscopeinferred)
399             buf.writestring("Nl");
400 
401         if (ta.islive)
402             buf.writestring("Nm");
403 
404         switch (ta.trust)
405         {
406             case TRUST.trusted:
407                 buf.writestring("Ne");
408                 break;
409             case TRUST.safe:
410                 buf.writestring("Nf");
411                 break;
412             default:
413                 break;
414         }
415 
416         // Write argument types
417         paramsToDecoBuffer(t.parameterList.parameters);
418         //if (buf.data[buf.length - 1] == '@') assert(0);
419         buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
420         if (tret !is null)
421             visitWithMask(tret, 0);
422         t.inuse--;
423     }
424 
425     override void visit(TypeIdentifier t)
426     {
427         visit(cast(Type)t);
428         auto name = t.ident.toString();
429         buf.print(cast(int)name.length);
430         buf.writestring(name);
431     }
432 
433     override void visit(TypeEnum t)
434     {
435         visit(cast(Type)t);
436         mangleSymbol(t.sym);
437     }
438 
439     override void visit(TypeStruct t)
440     {
441         //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
442         visit(cast(Type)t);
443         mangleSymbol(t.sym);
444     }
445 
446     override void visit(TypeClass t)
447     {
448         //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
449         visit(cast(Type)t);
450         mangleSymbol(t.sym);
451     }
452 
453     override void visit(TypeTuple t)
454     {
455         //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
456         visit(cast(Type)t);
457         paramsToDecoBuffer(t.arguments);
458         buf.writeByte('Z');
459     }
460 
461     override void visit(TypeNull t)
462     {
463         visit(cast(Type)t);
464     }
465 
466     ////////////////////////////////////////////////////////////////////////////
467     void mangleDecl(Declaration sthis)
468     {
469         mangleParent(sthis);
470         assert(sthis.ident);
471         mangleIdentifier(sthis.ident, sthis);
472         if (FuncDeclaration fd = sthis.isFuncDeclaration())
473         {
474             mangleFunc(fd, false);
475         }
476         else if (sthis.type)
477         {
478             visitWithMask(sthis.type, 0);
479         }
480         else
481             assert(0);
482     }
483 
484     void mangleParent(Dsymbol s)
485     {
486         Dsymbol p;
487         if (TemplateInstance ti = s.isTemplateInstance())
488             p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent;
489         else
490             p = s.parent;
491         if (p)
492         {
493             mangleParent(p);
494             auto ti = p.isTemplateInstance();
495             if (ti && !ti.isTemplateMixin())
496             {
497                 mangleTemplateInstance(ti);
498             }
499             else if (p.getIdent())
500             {
501                 mangleIdentifier(p.ident, s);
502                 if (FuncDeclaration f = p.isFuncDeclaration())
503                     mangleFunc(f, true);
504             }
505             else
506                 buf.writeByte('0');
507         }
508     }
509 
510     void mangleFunc(FuncDeclaration fd, bool inParent)
511     {
512         //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
513         //printf("fd.type = %s\n", fd.type.toChars());
514         if (fd.needThis() || fd.isNested())
515             buf.writeByte('M');
516 
517         if (!fd.type || fd.type.ty == Terror)
518         {
519             // never should have gotten here, but could be the result of
520             // failed speculative compilation
521             buf.writestring("9__error__FZ");
522 
523             //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars());
524             //assert(0); // don't mangle function until semantic3 done.
525         }
526         else if (inParent)
527         {
528             TypeFunction tf = fd.type.isTypeFunction();
529             TypeFunction tfo = fd.originalType.isTypeFunction();
530             mangleFuncType(tf, tfo, 0, null);
531         }
532         else
533         {
534             visitWithMask(fd.type, 0);
535         }
536     }
537 
538     /************************************************************
539      * Write length prefixed string to buf.
540      */
541     extern (D) void toBuffer(const(char)[] id, Dsymbol s)
542     {
543         const len = id.length;
544         if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
545             s.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf.length + len));
546         else
547         {
548             buf.print(len);
549             buf.writestring(id);
550         }
551     }
552 
553     /************************************************************
554      * Try to obtain an externally mangled identifier from a declaration.
555      * If the declaration is at global scope or mixed in at global scope,
556      * the user might want to call it externally, so an externally mangled
557      * name is returned. Member functions or nested functions can't be called
558      * externally in C, so in that case null is returned. C++ does support
559      * namespaces, so extern(C++) always gives a C++ mangled name.
560      *
561      * See also: https://issues.dlang.org/show_bug.cgi?id=20012
562      *
563      * Params:
564      *     d = declaration to mangle
565      *
566      * Returns:
567      *     an externally mangled name or null if the declaration cannot be called externally
568      */
569     extern (D) static const(char)[] externallyMangledIdentifier(Declaration d)
570     {
571         const par = d.toParent(); //toParent() skips over mixin templates
572         if (!par || par.isModule() || d.linkage == LINK.cpp)
573         {
574             final switch (d.linkage)
575             {
576                 case LINK.d:
577                     break;
578                 case LINK.c:
579                 case LINK.windows:
580                 case LINK.pascal:
581                 case LINK.objc:
582                     return d.ident.toString();
583                 case LINK.cpp:
584                 {
585                     const p = target.cpp.toMangle(d);
586                     return p.toDString();
587                 }
588                 case LINK.default_:
589                 case LINK.system:
590                     d.error("forward declaration");
591                     return d.ident.toString();
592             }
593         }
594         return null;
595     }
596 
597     override void visit(Declaration d)
598     {
599         //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
600         //        d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
601         if (const id = externallyMangledIdentifier(d))
602         {
603             buf.writestring(id);
604             return;
605         }
606         buf.writestring("_D");
607         mangleDecl(d);
608         debug
609         {
610             const slice = (*buf)[];
611             assert(slice.length);
612             for (size_t pos; pos < slice.length; )
613             {
614                 dchar c;
615                 auto ppos = pos;
616                 const s = utf_decodeChar(slice, pos, c);
617                 assert(s is null, s);
618                 assert(c.isValidMangling, "The mangled name '" ~ slice ~ "' " ~
619                     "contains an invalid character: " ~ slice[ppos..pos]);
620             }
621         }
622     }
623 
624     /******************************************************************************
625      * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
626      * If and only if there is no overloads, mangle() could return
627      * exact mangled name.
628      *
629      *      module test;
630      *      void foo(long) {}           // _D4test3fooFlZv
631      *      void foo(string) {}         // _D4test3fooFAyaZv
632      *
633      *      // from FuncDeclaration.mangle().
634      *      pragma(msg, foo.mangleof);  // prints unexact mangled name "4test3foo"
635      *                                  // by calling Dsymbol.mangle()
636      *
637      *      // from FuncAliasDeclaration.mangle()
638      *      pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof);  // "_D4test3fooFlZv"
639      *      pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof);  // "_D4test3fooFAyaZv"
640      *
641      * If a function has no overloads, .mangleof property still returns exact mangled name.
642      *
643      *      void bar() {}
644      *      pragma(msg, bar.mangleof);  // still prints "_D4test3barFZv"
645      *                                  // by calling FuncDeclaration.mangleExact().
646      */
647     override void visit(FuncDeclaration fd)
648     {
649         if (fd.isUnique())
650             mangleExact(fd);
651         else
652             visit(cast(Dsymbol)fd);
653     }
654 
655     // ditto
656     override void visit(FuncAliasDeclaration fd)
657     {
658         FuncDeclaration f = fd.toAliasFunc();
659         FuncAliasDeclaration fa = f.isFuncAliasDeclaration();
660         if (!fd.hasOverloads && !fa)
661         {
662             mangleExact(f);
663             return;
664         }
665         if (fa)
666         {
667             mangleSymbol(fa);
668             return;
669         }
670         visit(cast(Dsymbol)fd);
671     }
672 
673     override void visit(OverDeclaration od)
674     {
675         if (od.overnext)
676         {
677             visit(cast(Dsymbol)od);
678             return;
679         }
680         if (FuncDeclaration fd = od.aliassym.isFuncDeclaration())
681         {
682             if (!od.hasOverloads || fd.isUnique())
683             {
684                 mangleExact(fd);
685                 return;
686             }
687         }
688         if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration())
689         {
690             if (!od.hasOverloads || td.overnext is null)
691             {
692                 mangleSymbol(td);
693                 return;
694             }
695         }
696         visit(cast(Dsymbol)od);
697     }
698 
699     void mangleExact(FuncDeclaration fd)
700     {
701         assert(!fd.isFuncAliasDeclaration());
702         if (fd.mangleOverride)
703         {
704             buf.writestring(fd.mangleOverride);
705             return;
706         }
707         if (fd.isMain())
708         {
709             buf.writestring("_Dmain");
710             return;
711         }
712         if (fd.isWinMain() || fd.isDllMain())
713         {
714             buf.writestring(fd.ident.toString());
715             return;
716         }
717         visit(cast(Declaration)fd);
718     }
719 
720     override void visit(VarDeclaration vd)
721     {
722         if (vd.mangleOverride)
723         {
724             buf.writestring(vd.mangleOverride);
725             return;
726         }
727         visit(cast(Declaration)vd);
728     }
729 
730     override void visit(AggregateDeclaration ad)
731     {
732         ClassDeclaration cd = ad.isClassDeclaration();
733         Dsymbol parentsave = ad.parent;
734         if (cd)
735         {
736             /* These are reserved to the compiler, so keep simple
737              * names for them.
738              */
739             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)
740             {
741                 // Don't mangle parent
742                 ad.parent = null;
743             }
744         }
745         visit(cast(Dsymbol)ad);
746         ad.parent = parentsave;
747     }
748 
749     override void visit(TemplateInstance ti)
750     {
751         version (none)
752         {
753             printf("TemplateInstance.mangle() %p %s", ti, ti.toChars());
754             if (ti.parent)
755                 printf("  parent = %s %s", ti.parent.kind(), ti.parent.toChars());
756             printf("\n");
757         }
758         if (!ti.tempdecl)
759             ti.error("is not defined");
760         else
761             mangleParent(ti);
762 
763         if (ti.isTemplateMixin() && ti.ident)
764             mangleIdentifier(ti.ident, ti);
765         else
766             mangleTemplateInstance(ti);
767     }
768 
769     void mangleTemplateInstance(TemplateInstance ti)
770     {
771         TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration();
772         assert(tempdecl);
773 
774         // Use "__U" for the symbols declared inside template constraint.
775         const char T = ti.members ? 'T' : 'U';
776         buf.printf("__%c", T);
777         mangleIdentifier(tempdecl.ident, tempdecl);
778 
779         auto args = ti.tiargs;
780         size_t nparams = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0);
781         for (size_t i = 0; i < args.dim; i++)
782         {
783             auto o = (*args)[i];
784             Type ta = isType(o);
785             Expression ea = isExpression(o);
786             Dsymbol sa = isDsymbol(o);
787             Tuple va = isTuple(o);
788             //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
789             if (i < nparams && (*tempdecl.parameters)[i].specialization())
790                 buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
791             if (ta)
792             {
793                 buf.writeByte('T');
794                 visitWithMask(ta, 0);
795             }
796             else if (ea)
797             {
798                 // Don't interpret it yet, it might actually be an alias template parameter.
799                 // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
800                 enum keepLvalue = true;
801                 ea = ea.optimize(WANTvalue, keepLvalue);
802                 if (auto ev = ea.isVarExp())
803                 {
804                     sa = ev.var;
805                     ea = null;
806                     goto Lsa;
807                 }
808                 if (auto et = ea.isThisExp())
809                 {
810                     sa = et.var;
811                     ea = null;
812                     goto Lsa;
813                 }
814                 if (auto ef = ea.isFuncExp())
815                 {
816                     if (ef.td)
817                         sa = ef.td;
818                     else
819                         sa = ef.fd;
820                     ea = null;
821                     goto Lsa;
822                 }
823                 buf.writeByte('V');
824                 if (ea.op == TOK.tuple)
825                 {
826                     ea.error("tuple is not a valid template value argument");
827                     continue;
828                 }
829                 // Now that we know it is not an alias, we MUST obtain a value
830                 uint olderr = global.errors;
831                 ea = ea.ctfeInterpret();
832                 if (ea.op == TOK.error || olderr != global.errors)
833                     continue;
834 
835                 /* Use type mangling that matches what it would be for a function parameter
836                 */
837                 visitWithMask(ea.type, 0);
838                 ea.accept(this);
839             }
840             else if (sa)
841             {
842             Lsa:
843                 sa = sa.toAlias();
844                 if (Declaration d = sa.isDeclaration())
845                 {
846                     if (auto fad = d.isFuncAliasDeclaration())
847                         d = fad.toAliasFunc();
848                     if (d.mangleOverride)
849                     {
850                         buf.writeByte('X');
851                         toBuffer(d.mangleOverride, d);
852                         continue;
853                     }
854                     if (const id = externallyMangledIdentifier(d))
855                     {
856                         buf.writeByte('X');
857                         toBuffer(id, d);
858                         continue;
859                     }
860                     if (!d.type || !d.type.deco)
861                     {
862                         ti.error("forward reference of %s `%s`", d.kind(), d.toChars());
863                         continue;
864                     }
865                 }
866                 buf.writeByte('S');
867                 mangleSymbol(sa);
868             }
869             else if (va)
870             {
871                 assert(i + 1 == args.dim); // must be last one
872                 args = &va.objects;
873                 i = -cast(size_t)1;
874             }
875             else
876                 assert(0);
877         }
878         buf.writeByte('Z');
879     }
880 
881     override void visit(Dsymbol s)
882     {
883         version (none)
884         {
885             printf("Dsymbol.mangle() '%s'", s.toChars());
886             if (s.parent)
887                 printf("  parent = %s %s", s.parent.kind(), s.parent.toChars());
888             printf("\n");
889         }
890         mangleParent(s);
891         if (s.ident)
892             mangleIdentifier(s.ident, s);
893         else
894             toBuffer(s.toString(), s);
895         //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
896     }
897 
898     ////////////////////////////////////////////////////////////////////////////
899     override void visit(Expression e)
900     {
901         e.error("expression `%s` is not a valid template value argument", e.toChars());
902     }
903 
904     override void visit(IntegerExp e)
905     {
906         const v = e.toInteger();
907         if (cast(sinteger_t)v < 0)
908         {
909             buf.writeByte('N');
910             buf.print(-v);
911         }
912         else
913         {
914             buf.writeByte('i');
915             buf.print(v);
916         }
917     }
918 
919     override void visit(RealExp e)
920     {
921         buf.writeByte('e');
922         realToMangleBuffer(e.value);
923     }
924 
925     void realToMangleBuffer(real_t value)
926     {
927         /* Rely on %A to get portable mangling.
928          * Must munge result to get only identifier characters.
929          *
930          * Possible values from %A  => mangled result
931          * NAN                      => NAN
932          * -INF                     => NINF
933          * INF                      => INF
934          * -0X1.1BC18BA997B95P+79   => N11BC18BA997B95P79
935          * 0X1.9P+2                 => 19P2
936          */
937         if (CTFloat.isNaN(value))
938         {
939             buf.writestring("NAN"); // no -NAN bugs
940             return;
941         }
942 
943         if (value < CTFloat.zero)
944         {
945             buf.writeByte('N');
946             value = -value;
947         }
948 
949         if (CTFloat.isInfinity(value))
950         {
951             buf.writestring("INF");
952             return;
953         }
954 
955         char[36] buffer = void;
956         // 'A' format yields [-]0xh.hhhhp+-d
957         const n = CTFloat.sprint(buffer.ptr, 'A', value);
958         assert(n < buffer.length);
959         foreach (const c; buffer[2 .. n])
960         {
961             switch (c)
962             {
963                 case '-':
964                     buf.writeByte('N');
965                     break;
966 
967                 case '+':
968                 case '.':
969                     break;
970 
971                 default:
972                     buf.writeByte(c);
973                     break;
974             }
975         }
976     }
977 
978     override void visit(ComplexExp e)
979     {
980         buf.writeByte('c');
981         realToMangleBuffer(e.toReal());
982         buf.writeByte('c'); // separate the two
983         realToMangleBuffer(e.toImaginary());
984     }
985 
986     override void visit(NullExp e)
987     {
988         buf.writeByte('n');
989     }
990 
991     override void visit(StringExp e)
992     {
993         char m;
994         OutBuffer tmp;
995         const(char)[] q;
996         /* Write string in UTF-8 format
997          */
998         switch (e.sz)
999         {
1000         case 1:
1001             m = 'a';
1002             q = e.peekString();
1003             break;
1004         case 2:
1005         {
1006             m = 'w';
1007             const slice = e.peekWstring();
1008             for (size_t u = 0; u < e.len;)
1009             {
1010                 dchar c;
1011                 if (const s = utf_decodeWchar(slice, u, c))
1012                     e.error("%.*s", cast(int)s.length, s.ptr);
1013                 else
1014                     tmp.writeUTF8(c);
1015             }
1016             q = tmp[];
1017             break;
1018         }
1019         case 4:
1020         {
1021             m = 'd';
1022             const slice = e.peekDstring();
1023             foreach (c; slice)
1024             {
1025                 if (!utf_isValidDchar(c))
1026                     e.error("invalid UCS-32 char \\U%08x", c);
1027                 else
1028                     tmp.writeUTF8(c);
1029             }
1030             q = tmp[];
1031             break;
1032         }
1033 
1034         default:
1035             assert(0);
1036         }
1037         buf.reserve(1 + 11 + 2 * q.length);
1038         buf.writeByte(m);
1039         buf.print(q.length);
1040         buf.writeByte('_');    // nbytes <= 11
1041         auto slice = buf.allocate(2 * q.length);
1042         foreach (i, c; q)
1043         {
1044             char hi = (c >> 4) & 0xF;
1045             slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a');
1046             char lo = c & 0xF;
1047             slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a');
1048         }
1049     }
1050 
1051     override void visit(ArrayLiteralExp e)
1052     {
1053         const dim = e.elements ? e.elements.dim : 0;
1054         buf.writeByte('A');
1055         buf.print(dim);
1056         foreach (i; 0 .. dim)
1057         {
1058             e[i].accept(this);
1059         }
1060     }
1061 
1062     override void visit(AssocArrayLiteralExp e)
1063     {
1064         const dim = e.keys.dim;
1065         buf.writeByte('A');
1066         buf.print(dim);
1067         foreach (i; 0 .. dim)
1068         {
1069             (*e.keys)[i].accept(this);
1070             (*e.values)[i].accept(this);
1071         }
1072     }
1073 
1074     override void visit(StructLiteralExp e)
1075     {
1076         const dim = e.elements ? e.elements.dim : 0;
1077         buf.writeByte('S');
1078         buf.print(dim);
1079         foreach (i; 0 .. dim)
1080         {
1081             Expression ex = (*e.elements)[i];
1082             if (ex)
1083                 ex.accept(this);
1084             else
1085                 buf.writeByte('v'); // 'v' for void
1086         }
1087     }
1088 
1089     ////////////////////////////////////////////////////////////////////////////
1090     void paramsToDecoBuffer(Parameters* parameters)
1091     {
1092         //printf("Parameter.paramsToDecoBuffer()\n");
1093 
1094         int paramsToDecoBufferDg(size_t n, Parameter p)
1095         {
1096             p.accept(this);
1097             return 0;
1098         }
1099 
1100         Parameter._foreach(parameters, &paramsToDecoBufferDg);
1101     }
1102 
1103     override void visit(Parameter p)
1104     {
1105         if (p.storageClass & STC.scope_ && !(p.storageClass & STC.scopeinferred))
1106             buf.writeByte('M');
1107 
1108         // 'return inout ref' is the same as 'inout ref'
1109         if ((p.storageClass & (STC.return_ | STC.wild)) == STC.return_ &&
1110             !(p.storageClass & STC.returninferred))
1111             buf.writestring("Nk");
1112         switch (p.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.lazy_))
1113         {
1114         case 0:
1115         case STC.in_:
1116             break;
1117         case STC.out_:
1118             buf.writeByte('J');
1119             break;
1120         case STC.ref_:
1121             buf.writeByte('K');
1122             break;
1123         case STC.lazy_:
1124             buf.writeByte('L');
1125             break;
1126         default:
1127             debug
1128             {
1129                 printf("storageClass = x%llx\n", p.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.lazy_));
1130             }
1131             assert(0);
1132         }
1133         visitWithMask(p.type, 0);
1134     }
1135 }
1136 
1137 /// Returns: `true` if the given character is a valid mangled character
1138 package bool isValidMangling(dchar c) nothrow
1139 {
1140     return
1141         c >= 'A' && c <= 'Z' ||
1142         c >= 'a' && c <= 'z' ||
1143         c >= '0' && c <= '9' ||
1144         c != 0 && strchr("$%().:?@[]_", c) ||
1145         isUniAlpha(c);
1146 }
1147 
1148 // valid mangled characters
1149 unittest
1150 {
1151     assert('a'.isValidMangling);
1152     assert('B'.isValidMangling);
1153     assert('2'.isValidMangling);
1154     assert('@'.isValidMangling);
1155     assert('_'.isValidMangling);
1156 }
1157 
1158 // invalid mangled characters
1159 unittest
1160 {
1161     assert(!'-'.isValidMangling);
1162     assert(!0.isValidMangling);
1163     assert(!'/'.isValidMangling);
1164     assert(!'\\'.isValidMangling);
1165 }
1166 
1167 /******************************************************************************
1168  * Returns exact mangled name of function.
1169  */
1170 extern (C++) const(char)* mangleExact(FuncDeclaration fd)
1171 {
1172     if (!fd.mangleString)
1173     {
1174         OutBuffer buf;
1175         scope Mangler v = new Mangler(&buf);
1176         v.mangleExact(fd);
1177         fd.mangleString = buf.extractChars();
1178     }
1179     return fd.mangleString;
1180 }
1181 
1182 extern (C++) void mangleToBuffer(Type t, OutBuffer* buf)
1183 {
1184     if (t.deco)
1185         buf.writestring(t.deco);
1186     else
1187     {
1188         scope Mangler v = new Mangler(buf);
1189         v.visitWithMask(t, 0);
1190     }
1191 }
1192 
1193 extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf)
1194 {
1195     scope Mangler v = new Mangler(buf);
1196     e.accept(v);
1197 }
1198 
1199 extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf)
1200 {
1201     scope Mangler v = new Mangler(buf);
1202     s.accept(v);
1203 }
1204 
1205 extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf)
1206 {
1207     scope Mangler v = new Mangler(buf);
1208     v.mangleTemplateInstance(ti);
1209 }
1210 
1211 /******************************************************************************
1212  * Mangle function signatures ('this' qualifier, and parameter types)
1213  * to check conflicts in function overloads.
1214  * It's different from fd.type.deco. For example, fd.type.deco would be null
1215  * if fd is an auto function.
1216  *
1217  * Params:
1218  *    buf = `OutBuffer` to write the mangled function signature to
1219 *     fd  = `FuncDeclaration` to mangle
1220  */
1221 void mangleToFuncSignature(ref OutBuffer buf, FuncDeclaration fd)
1222 {
1223     auto tf = fd.type.isTypeFunction();
1224 
1225     scope Mangler v = new Mangler(&buf);
1226 
1227     MODtoDecoBuffer(&buf, tf.mod);
1228     v.paramsToDecoBuffer(tf.parameterList.parameters);
1229     buf.writeByte('Z' - tf.parameterList.varargs);
1230 }