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