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