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