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