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