d: Merge upstream dmd, druntime 4c18eed967, phobos d945686a4.
[official-gcc.git] / gcc / d / dmd / dmangle.d
blob8fdb1ae835c5be44ff54a22aa290173c81d342ee
1 /**
2 * Does name mangling for `extern(D)` symbols.
4 * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling)
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/
15 module dmd.dmangle;
18 /******************************************************************************
19 * Returns exact mangled name of function.
21 extern (C++) const(char)* mangleExact(FuncDeclaration fd)
23 //printf("mangleExact()\n");
24 if (!fd.mangleString)
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();
32 return fd.mangleString;
35 extern (C++) void mangleToBuffer(Type t, ref OutBuffer buf)
37 //printf("mangleToBuffer t()\n");
38 if (t.deco)
39 buf.writestring(t.deco);
40 else
42 auto backref = Backref(t);
43 mangleType(t, 0, buf, backref);
44 //printf("%s\n", buf.peekChars());
48 extern (C++) void mangleToBuffer(Expression e, ref OutBuffer buf)
50 //printf("mangleToBuffer e()\n");
51 auto backref = Backref(null);
52 scope Mangler v = new Mangler(buf, &backref);
53 e.accept(v);
56 extern (C++) void mangleToBuffer(Dsymbol s, ref OutBuffer buf)
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);
64 extern (C++) void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
66 //printf("mangleToBuffer ti()\n");
67 auto backref = Backref(null);
68 scope Mangler v = new Mangler(buf, &backref);
69 v.mangleTemplateInstance(ti);
72 /// Returns: `true` if the given character is a valid mangled character
73 package bool isValidMangling(dchar c) nothrow
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);
83 // valid mangled characters
84 unittest
86 assert('a'.isValidMangling);
87 assert('B'.isValidMangling);
88 assert('2'.isValidMangling);
89 assert('@'.isValidMangling);
90 assert('_'.isValidMangling);
93 // invalid mangled characters
94 unittest
96 assert(!'-'.isValidMangling);
97 assert(!0.isValidMangling);
98 assert(!'/'.isValidMangling);
99 assert(!'\\'.isValidMangling);
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
112 public Type decoToType(const(char)[] deco)
114 //printf("decoToType(): %.*s\n", cast(int)deco.length, deco.ptr);
115 if (auto sv = Type.stringtable.lookup(deco))
117 if (sv.value)
119 Type t = cast(Type)sv.value;
120 assert(t.deco);
121 return t;
124 return null;
128 /***************************************** private ***************************************/
130 private:
133 import core.stdc.ctype;
134 import core.stdc.stdio;
135 import core.stdc.string;
137 import dmd.aggregate;
138 import dmd.arraytypes;
139 import dmd.astenums;
140 import dmd.dclass;
141 import dmd.declaration;
142 import dmd.dmodule;
143 import dmd.dsymbol;
144 import dmd.dtemplate;
145 import dmd.errors;
146 import dmd.expression;
147 import dmd.func;
148 import dmd.globals;
149 import dmd.id;
150 import dmd.identifier;
151 import dmd.mtype;
152 import dmd.root.ctfloat;
153 import dmd.common.outbuffer;
154 import dmd.root.aav;
155 import dmd.root.string;
156 import dmd.root.stringtable;
157 import dmd.root.utf;
158 import dmd.target;
159 import dmd.tokens;
160 import dmd.visitor;
162 private immutable char[TMAX] mangleChar =
164 Tchar : 'a',
165 Tbool : 'b',
166 Tcomplex80 : 'c',
167 Tfloat64 : 'd',
168 Tfloat80 : 'e',
169 Tfloat32 : 'f',
170 Tint8 : 'g',
171 Tuns8 : 'h',
172 Tint32 : 'i',
173 Timaginary80 : 'j',
174 Tuns32 : 'k',
175 Tint64 : 'l',
176 Tuns64 : 'm',
177 Tnull : 'n',
178 Timaginary32 : 'o',
179 Timaginary64 : 'p',
180 Tcomplex32 : 'q',
181 Tcomplex64 : 'r',
182 Tint16 : 's',
183 Tuns16 : 't',
184 Twchar : 'u',
185 Tvoid : 'v',
186 Tdchar : 'w',
187 // x // const
188 // y // immutable
189 Tint128 : 'z', // zi
190 Tuns128 : 'z', // zk
192 Tarray : 'A',
193 Ttuple : 'B',
194 Tclass : 'C',
195 Tdelegate : 'D',
196 Tenum : 'E',
197 Tfunction : 'F', // D function
198 Tsarray : 'G',
199 Taarray : 'H',
200 // I // in
201 // J // out
202 // K // ref
203 // L // lazy
204 // M // has this, or scope
205 // N // Nh:vector Ng:wild Nn:noreturn
206 // O // shared
207 Tpointer : 'P',
208 // Q // Type/symbol/identifier backward reference
209 Treference : 'R',
210 Tstruct : 'S',
211 // T // Ttypedef
212 // U // C function
213 // W // Windows function
214 // X // variadic T t...)
215 // Y // variadic T t,...)
216 // Z // not variadic, end of parameters
218 // '@' shouldn't appear anywhere in the deco'd names
219 Tnone : '@',
220 Tident : '@',
221 Tinstance : '@',
222 Terror : '@',
223 Ttypeof : '@',
224 Tslice : '@',
225 Treturn : '@',
226 Tvector : '@',
227 Ttraits : '@',
228 Tmixin : '@',
229 Ttag : '@',
230 Tnoreturn : '@', // becomes 'Nn'
233 unittest
235 foreach (i, mangle; mangleChar)
237 if (mangle == char.init)
239 fprintf(stderr, "ty = %u\n", cast(uint)i);
240 assert(0);
245 /************************************************
246 * Append the mangling of type `t` to `buf`.
247 * Params:
248 * t = type to mangle
249 * modMask = mod bits currently applying to t
250 * buf = buffer to append mangling to
251 * backref = state of back references (updated)
253 void mangleType(Type t, ubyte modMask, ref OutBuffer buf, ref Backref backref)
255 void visitWithMask(Type t, ubyte modMask)
257 void mangleSymbol(Dsymbol s)
259 scope Mangler v = new Mangler(buf, &backref);
260 v.mangleSymbol(s);
263 void visitType(Type t)
265 tyToDecoBuffer(buf, t.ty);
268 void visitTypeNext(TypeNext t)
270 visitType(t);
271 visitWithMask(t.next, t.mod);
274 void visitTypeVector(TypeVector t)
276 buf.writestring("Nh");
277 visitWithMask(t.basetype, t.mod);
280 void visitTypeSArray(TypeSArray t)
282 visitType(t);
283 if (t.dim)
284 buf.print(t.dim.toInteger());
285 if (t.next)
286 visitWithMask(t.next, t.mod);
289 void visitTypeDArray(TypeDArray t)
291 visitType(t);
292 if (t.next)
293 visitWithMask(t.next, t.mod);
296 void visitTypeAArray(TypeAArray t)
298 visitType(t);
299 visitWithMask(t.index, 0);
300 visitWithMask(t.next, t.mod);
303 void visitTypeFunction(TypeFunction t)
305 //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
306 //static int nest; if (++nest == 50) *(char*)0=0;
307 mangleFuncType(t, t, t.mod, t.next, buf, backref);
310 void visitTypeIdentifier(TypeIdentifier t)
312 visitType(t);
313 auto name = t.ident.toString();
314 buf.print(cast(int)name.length);
315 buf.writestring(name);
318 void visitTypeEnum(TypeEnum t)
320 visitType(t);
321 mangleSymbol(t.sym);
324 void visitTypeStruct(TypeStruct t)
326 //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
327 visitType(t);
328 mangleSymbol(t.sym);
331 void visitTypeClass(TypeClass t)
333 //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
334 visitType(t);
335 mangleSymbol(t.sym);
338 void visitTypeTuple(TypeTuple t)
340 //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
341 visitType(t);
342 Parameter._foreach(t.arguments, (idx, param) {
343 mangleParameter(param, buf, backref);
344 return 0;
346 buf.writeByte('Z');
349 void visitTypeNull(TypeNull t)
351 visitType(t);
354 void visitTypeNoreturn(TypeNoreturn t)
356 buf.writestring("Nn");
359 if (modMask != t.mod)
361 MODtoDecoBuffer(buf, t.mod);
363 if (backref.addRefToType(buf, t))
364 return;
366 switch (t.ty)
368 case Tpointer:
369 case Treference:
370 case Tdelegate:
371 case Tslice: visitTypeNext (cast(TypeNext)t); break;
373 case Tarray: visitTypeDArray (t.isTypeDArray()); break;
374 case Tsarray: visitTypeSArray (t.isTypeSArray()); break;
375 case Taarray: visitTypeAArray (t.isTypeAArray()); break;
376 case Tfunction: visitTypeFunction (t.isTypeFunction()); break;
377 case Tident: visitTypeIdentifier(t.isTypeIdentifier()); break;
378 case Tclass: visitTypeClass (t.isTypeClass()); break;
379 case Tstruct: visitTypeStruct (t.isTypeStruct()); break;
380 case Tenum: visitTypeEnum (t.isTypeEnum()); break;
381 case Ttuple: visitTypeTuple (t.isTypeTuple()); break;
382 case Tnull: visitTypeNull (t.isTypeNull()); break;
383 case Tvector: visitTypeVector (t.isTypeVector()); break;
384 case Tnoreturn: visitTypeNoreturn (t.isTypeNoreturn); break;
386 case Terror:
387 break; // ignore errors
389 default: visitType(t); break;
393 visitWithMask(t, modMask);
397 /*************************************************************
399 void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret, ref OutBuffer buf, ref Backref backref)
401 //printf("mangleFuncType() %s\n", t.toChars());
402 if (t.inuse && tret)
404 // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
405 t.inuse = 2; // flag error to caller
406 return;
408 t.inuse++;
409 if (modMask != t.mod)
410 MODtoDecoBuffer(buf, t.mod);
412 char mc;
413 final switch (t.linkage)
415 case LINK.default_:
416 case LINK.d:
417 mc = 'F';
418 break;
419 case LINK.c:
420 mc = 'U';
421 break;
422 case LINK.windows:
423 mc = 'W';
424 break;
425 case LINK.cpp:
426 mc = 'R';
427 break;
428 case LINK.objc:
429 mc = 'Y';
430 break;
431 case LINK.system:
432 assert(0);
434 buf.writeByte(mc);
436 if (ta.purity)
437 buf.writestring("Na");
438 if (ta.isnothrow)
439 buf.writestring("Nb");
440 if (ta.isref)
441 buf.writestring("Nc");
442 if (ta.isproperty)
443 buf.writestring("Nd");
444 if (ta.isnogc)
445 buf.writestring("Ni");
447 // `return scope` must be in that order
448 if (ta.isreturnscope && !ta.isreturninferred)
450 buf.writestring("NjNl");
452 else
454 // when return ref, the order is `scope return`
455 if (ta.isScopeQual && !ta.isscopeinferred)
456 buf.writestring("Nl");
458 if (ta.isreturn && !ta.isreturninferred)
459 buf.writestring("Nj");
462 if (ta.islive)
463 buf.writestring("Nm");
465 switch (ta.trust)
467 case TRUST.trusted:
468 buf.writestring("Ne");
469 break;
470 case TRUST.safe:
471 buf.writestring("Nf");
472 break;
473 default:
474 break;
477 // Write argument types
478 foreach (idx, param; t.parameterList)
479 mangleParameter(param, buf, backref);
480 //if (buf.data[buf.length - 1] == '@') assert(0);
481 buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
482 if (tret !is null)
483 mangleType(tret, 0, buf, backref);
484 t.inuse--;
487 /*************************************************************
489 void mangleParameter(Parameter p, ref OutBuffer buf, ref Backref backref)
491 // https://dlang.org/spec/abi.html#Parameter
493 auto stc = p.storageClass;
495 // Inferred storage classes don't get mangled in
496 if (stc & STC.scopeinferred)
497 stc &= ~(STC.scope_ | STC.scopeinferred);
498 if (stc & STC.returninferred)
499 stc &= ~(STC.return_ | STC.returninferred);
501 // much like hdrgen.stcToBuffer()
502 string rrs;
503 const isout = (stc & STC.out_) != 0;
504 final switch (buildScopeRef(stc))
506 case ScopeRef.None:
507 case ScopeRef.Scope:
508 case ScopeRef.Ref:
509 case ScopeRef.Return:
510 case ScopeRef.RefScope:
511 break;
513 case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope
514 case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref
515 case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref
516 case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref
518 buf.writestring(rrs);
519 stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
520 break;
523 if (stc & STC.scope_)
524 buf.writeByte('M'); // scope
526 if (stc & STC.return_)
527 buf.writestring("Nk"); // return
529 switch (stc & (STC.IOR | STC.lazy_))
531 case 0:
532 break;
533 case STC.in_:
534 buf.writeByte('I');
535 break;
536 case STC.in_ | STC.ref_:
537 buf.writestring("IK");
538 break;
539 case STC.out_:
540 buf.writeByte('J');
541 break;
542 case STC.ref_:
543 buf.writeByte('K');
544 break;
545 case STC.lazy_:
546 buf.writeByte('L');
547 break;
548 default:
549 debug
551 printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_));
553 assert(0);
555 mangleType(p.type, (stc & STC.in_) ? MODFlags.const_ : 0, buf, backref);
559 private extern (C++) final class Mangler : Visitor
561 alias visit = Visitor.visit;
562 public:
563 static assert(Key.sizeof == size_t.sizeof);
565 OutBuffer* buf;
566 Backref* backref;
568 extern (D) this(ref OutBuffer buf, Backref* backref) @trusted
570 this.buf = &buf;
571 this.backref = backref;
574 void mangleSymbol(Dsymbol s)
576 s.accept(this);
579 void mangleIdentifier(Identifier id, Dsymbol s)
581 if (!backref.addRefToIdentifier(*buf, id))
582 toBuffer(*buf, id.toString(), s);
585 ////////////////////////////////////////////////////////////////////////////
586 void mangleDecl(Declaration sthis)
588 mangleParent(sthis);
589 assert(sthis.ident);
590 mangleIdentifier(sthis.ident, sthis);
591 if (FuncDeclaration fd = sthis.isFuncDeclaration())
593 mangleFunc(fd, false);
595 else if (sthis.type)
597 mangleType(sthis.type, 0, *buf, *backref);
599 else
600 assert(0);
603 void mangleParent(Dsymbol s)
605 //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
606 Dsymbol p;
607 if (TemplateInstance ti = s.isTemplateInstance())
608 p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent;
609 else
610 p = s.parent;
611 if (p)
613 uint localNum = s.localNum;
614 mangleParent(p);
615 auto ti = p.isTemplateInstance();
616 if (ti && !ti.isTemplateMixin())
618 localNum = ti.tempdecl.localNum;
619 mangleTemplateInstance(ti);
621 else if (p.getIdent())
623 mangleIdentifier(p.ident, s);
624 if (FuncDeclaration f = p.isFuncDeclaration())
625 mangleFunc(f, true);
627 else
628 buf.writeByte('0');
630 if (localNum)
631 writeLocalParent(*buf, localNum);
635 void mangleFunc(FuncDeclaration fd, bool inParent)
637 //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
638 //printf("fd.type = %s\n", fd.type.toChars());
639 if (fd.needThis() || fd.isNested())
640 buf.writeByte('M');
642 if (!fd.type || fd.type.ty == Terror)
644 // never should have gotten here, but could be the result of
645 // failed speculative compilation
646 buf.writestring("9__error__FZ");
648 //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars());
649 //assert(0); // don't mangle function until semantic3 done.
651 else if (inParent)
653 TypeFunction tf = fd.type.isTypeFunction();
654 TypeFunction tfo = fd.originalType.isTypeFunction();
655 mangleFuncType(tf, tfo, 0, null, *buf, *backref);
657 else
659 mangleType(fd.type, 0, *buf, *backref);
663 override void visit(Declaration d)
665 //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
666 // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
667 if (const id = externallyMangledIdentifier(d))
669 buf.writestring(id);
670 return;
672 buf.writestring("_D");
673 mangleDecl(d);
674 debug
676 const slice = (*buf)[];
677 assert(slice.length);
678 for (size_t pos; pos < slice.length; )
680 dchar c;
681 auto ppos = pos;
682 const s = utf_decodeChar(slice, pos, c);
683 assert(s is null, s);
684 assert(c.isValidMangling, "The mangled name '" ~ slice ~ "' " ~
685 "contains an invalid character: " ~ slice[ppos..pos]);
690 /******************************************************************************
691 * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
692 * If and only if there is no overloads, mangle() could return
693 * exact mangled name.
695 * module test;
696 * void foo(long) {} // _D4test3fooFlZv
697 * void foo(string) {} // _D4test3fooFAyaZv
699 * // from FuncDeclaration.mangle().
700 * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
701 * // by calling Dsymbol.mangle()
703 * // from FuncAliasDeclaration.mangle()
704 * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
705 * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
707 * If a function has no overloads, .mangleof property still returns exact mangled name.
709 * void bar() {}
710 * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
711 * // by calling FuncDeclaration.mangleExact().
713 override void visit(FuncDeclaration fd)
715 if (fd.isUnique())
716 mangleExact(fd);
717 else
718 visit(cast(Dsymbol)fd);
721 // ditto
722 override void visit(FuncAliasDeclaration fd)
724 FuncDeclaration f = fd.toAliasFunc();
725 FuncAliasDeclaration fa = f.isFuncAliasDeclaration();
726 if (!fd.hasOverloads && !fa)
728 mangleExact(f);
729 return;
731 if (fa)
733 mangleSymbol(fa);
734 return;
736 visit(cast(Dsymbol)fd);
739 override void visit(OverDeclaration od)
741 if (od.overnext)
743 visit(cast(Dsymbol)od);
744 return;
746 if (FuncDeclaration fd = od.aliassym.isFuncDeclaration())
748 if (fd.isUnique())
750 mangleExact(fd);
751 return;
754 if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration())
756 if (td.overnext is null)
758 mangleSymbol(td);
759 return;
762 visit(cast(Dsymbol)od);
765 void mangleExact(FuncDeclaration fd)
767 assert(!fd.isFuncAliasDeclaration());
768 if (fd.mangleOverride)
770 buf.writestring(fd.mangleOverride);
771 return;
773 if (fd.isMain())
775 buf.writestring("_Dmain");
776 return;
778 if (fd.isWinMain() || fd.isDllMain())
780 buf.writestring(fd.ident.toString());
781 return;
783 visit(cast(Declaration)fd);
786 override void visit(VarDeclaration vd)
788 if (vd.mangleOverride)
790 buf.writestring(vd.mangleOverride);
791 return;
793 visit(cast(Declaration)vd);
796 override void visit(AggregateDeclaration ad)
798 ClassDeclaration cd = ad.isClassDeclaration();
799 Dsymbol parentsave = ad.parent;
800 if (cd)
802 /* These are reserved to the compiler, so keep simple
803 * names for them.
805 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 // Don't mangle parent
808 ad.parent = null;
811 visit(cast(Dsymbol)ad);
812 ad.parent = parentsave;
815 override void visit(TemplateInstance ti)
817 version (none)
819 printf("TemplateInstance.mangle() %p %s", ti, ti.toChars());
820 if (ti.parent)
821 printf(" parent = %s %s", ti.parent.kind(), ti.parent.toChars());
822 printf("\n");
824 if (!ti.tempdecl)
825 error(ti.loc, "%s `%s` is not defined", ti.kind, ti.toPrettyChars);
826 else
827 mangleParent(ti);
829 if (ti.isTemplateMixin() && ti.ident)
830 mangleIdentifier(ti.ident, ti);
831 else
832 mangleTemplateInstance(ti);
835 void mangleTemplateInstance(TemplateInstance ti)
837 TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration();
838 assert(tempdecl);
840 // Use "__U" for the symbols declared inside template constraint.
841 const char T = ti.members ? 'T' : 'U';
842 buf.printf("__%c", T);
843 mangleIdentifier(tempdecl.ident, tempdecl);
845 auto args = ti.tiargs;
846 size_t nparams = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
847 for (size_t i = 0; i < args.length; i++)
849 auto o = (*args)[i];
850 Type ta = isType(o);
851 Expression ea = isExpression(o);
852 Dsymbol sa = isDsymbol(o);
853 Tuple va = isTuple(o);
854 //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
855 if (i < nparams && (*tempdecl.parameters)[i].specialization())
856 buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
857 if (ta)
859 buf.writeByte('T');
860 mangleType(ta, 0, *buf, *backref);
862 else if (ea)
864 // Don't interpret it yet, it might actually be an alias template parameter.
865 // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
866 enum keepLvalue = true;
867 ea = ea.optimize(WANTvalue, keepLvalue);
868 if (auto ev = ea.isVarExp())
870 sa = ev.var;
871 ea = null;
872 goto Lsa;
874 if (auto et = ea.isThisExp())
876 sa = et.var;
877 ea = null;
878 goto Lsa;
880 if (auto ef = ea.isFuncExp())
882 if (ef.td)
883 sa = ef.td;
884 else
885 sa = ef.fd;
886 ea = null;
887 goto Lsa;
889 buf.writeByte('V');
890 if (ea.op == EXP.tuple)
892 error(ea.loc, "sequence is not a valid template value argument");
893 continue;
895 // Now that we know it is not an alias, we MUST obtain a value
896 uint olderr = global.errors;
897 ea = ea.ctfeInterpret();
898 if (ea.op == EXP.error || olderr != global.errors)
899 continue;
901 /* Use type mangling that matches what it would be for a function parameter
903 mangleType(ea.type, 0, *buf, *backref);
904 ea.accept(this);
906 else if (sa)
908 Lsa:
909 sa = sa.toAlias();
910 if (sa.isDeclaration() && !sa.isOverDeclaration())
912 Declaration d = sa.isDeclaration();
914 if (auto fad = d.isFuncAliasDeclaration())
915 d = fad.toAliasFunc();
916 if (d.mangleOverride)
918 buf.writeByte('X');
919 toBuffer(*buf, d.mangleOverride, d);
920 continue;
922 if (const id = externallyMangledIdentifier(d))
924 buf.writeByte('X');
925 toBuffer(*buf, id, d);
926 continue;
928 if (!d.type || !d.type.deco)
930 error(ti.loc, "%s `%s` forward reference of %s `%s`", ti.kind, ti.toPrettyChars, d.kind(), d.toChars());
931 continue;
934 buf.writeByte('S');
935 mangleSymbol(sa);
937 else if (va)
939 assert(i + 1 == args.length); // must be last one
940 args = &va.objects;
941 i = -cast(size_t)1;
943 else
944 assert(0);
946 buf.writeByte('Z');
949 override void visit(Dsymbol s)
951 version (none)
953 printf("Dsymbol.mangle() '%s'", s.toChars());
954 if (s.parent)
955 printf(" parent = %s %s", s.parent.kind(), s.parent.toChars());
956 printf("\n");
958 if (s.parent && s.ident)
960 if (auto m = s.parent.isModule())
962 if (m.filetype == FileType.c)
964 /* C types at global level get mangled into the __C global namespace
965 * to get the same mangling regardless of which module it
966 * is declared in. This works because types are the same if the mangling
967 * is the same.
969 mangleIdentifier(Id.ImportC, s); // parent
970 mangleIdentifier(s.ident, s);
971 return;
975 mangleParent(s);
976 if (s.ident)
977 mangleIdentifier(s.ident, s);
978 else
979 toBuffer(*buf, s.toString(), s);
980 //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
983 ////////////////////////////////////////////////////////////////////////////
984 override void visit(Expression e)
986 if (!e.type.isTypeError())
987 error(e.loc, "expression `%s` is not a valid template value argument", e.toChars());
990 override void visit(IntegerExp e)
992 const v = e.toInteger();
993 if (cast(sinteger_t)v < 0)
995 buf.writeByte('N');
996 buf.print(-v);
998 else
1000 buf.writeByte('i');
1001 buf.print(v);
1005 override void visit(RealExp e)
1007 buf.writeByte('e');
1008 realToMangleBuffer(*buf, e.value);
1011 override void visit(ComplexExp e)
1013 buf.writeByte('c');
1014 realToMangleBuffer(*buf, e.toReal());
1015 buf.writeByte('c'); // separate the two
1016 realToMangleBuffer(*buf, e.toImaginary());
1019 override void visit(NullExp e)
1021 buf.writeByte('n');
1024 override void visit(StringExp e)
1026 char m;
1027 OutBuffer tmp;
1028 const(char)[] q;
1029 /* Write string in UTF-8 format
1031 switch (e.sz)
1033 case 1:
1034 m = 'a';
1035 q = e.peekString();
1036 break;
1037 case 2:
1039 m = 'w';
1040 const slice = e.peekWstring();
1041 for (size_t u = 0; u < e.len;)
1043 dchar c;
1044 if (const s = utf_decodeWchar(slice, u, c))
1045 error(e.loc, "%.*s", cast(int)s.length, s.ptr);
1046 else
1047 tmp.writeUTF8(c);
1049 q = tmp[];
1050 break;
1052 case 4:
1054 m = 'd';
1055 const slice = e.peekDstring();
1056 foreach (c; slice)
1058 if (!utf_isValidDchar(c))
1059 error(e.loc, "invalid UCS-32 char \\U%08x", c);
1060 else
1061 tmp.writeUTF8(c);
1063 q = tmp[];
1064 break;
1067 default:
1068 assert(0);
1070 buf.reserve(1 + 11 + 2 * q.length);
1071 buf.writeByte(m);
1072 buf.print(q.length);
1073 buf.writeByte('_'); // nbytes <= 11
1074 auto slice = buf.allocate(2 * q.length);
1075 foreach (i, c; q)
1077 char hi = (c >> 4) & 0xF;
1078 slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a');
1079 char lo = c & 0xF;
1080 slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a');
1084 override void visit(ArrayLiteralExp e)
1086 const dim = e.elements ? e.elements.length : 0;
1087 buf.writeByte('A');
1088 buf.print(dim);
1089 foreach (i; 0 .. dim)
1091 e[i].accept(this);
1095 override void visit(AssocArrayLiteralExp e)
1097 const dim = e.keys.length;
1098 buf.writeByte('A');
1099 buf.print(dim);
1100 foreach (i; 0 .. dim)
1102 (*e.keys)[i].accept(this);
1103 (*e.values)[i].accept(this);
1107 override void visit(StructLiteralExp e)
1109 const dim = e.elements ? e.elements.length : 0;
1110 buf.writeByte('S');
1111 buf.print(dim);
1112 foreach (i; 0 .. dim)
1114 Expression ex = (*e.elements)[i];
1115 if (ex)
1116 ex.accept(this);
1117 else
1118 buf.writeByte('v'); // 'v' for void
1122 override void visit(FuncExp e)
1124 buf.writeByte('f');
1125 if (e.td)
1126 mangleSymbol(e.td);
1127 else
1128 mangleSymbol(e.fd);
1132 /***************************************
1133 * Manage back reference mangling
1135 private struct Backref
1138 * Back references a non-basic type
1140 * The encoded mangling is
1141 * 'Q' <relative position of first occurrence of type>
1143 * Params:
1144 * t = the type to encode via back referencing
1146 * Returns:
1147 * true if the type was found. A back reference has been encoded.
1148 * false if the type was not found. The current position is saved for later back references.
1150 bool addRefToType(ref OutBuffer buf, Type t)
1152 if (t.isTypeBasic())
1153 return false;
1156 * https://issues.dlang.org/show_bug.cgi?id=21591
1158 * Special case for unmerged TypeFunctions: use the generic merged
1159 * function type as backref cache key to avoid missed backrefs.
1161 * Merging is based on mangling, so we need to avoid an infinite
1162 * recursion by excluding the case where `t` is the root type passed to
1163 * `mangleToBuffer()`.
1165 if (t != rootType)
1167 if (t.isFunction_Delegate_PtrToFunction())
1169 t = t.merge2();
1173 return backrefImpl(buf, types, t);
1177 * Back references a single identifier
1179 * The encoded mangling is
1180 * 'Q' <relative position of first occurrence of type>
1182 * Params:
1183 * id = the identifier to encode via back referencing
1185 * Returns:
1186 * true if the identifier was found. A back reference has been encoded.
1187 * false if the identifier was not found. The current position is saved for later back references.
1189 bool addRefToIdentifier(ref OutBuffer buf, Identifier id)
1191 return backrefImpl(buf, idents, id);
1194 private:
1196 extern(D) bool backrefImpl(T)(ref OutBuffer buf, ref AssocArray!(T, size_t) aa, T key)
1198 auto p = aa.getLvalue(key);
1199 if (*p)
1201 const offset = *p - 1;
1202 writeBackRef(buf, buf.length - offset);
1203 return true;
1205 *p = buf.length + 1;
1206 return false;
1209 Type rootType; /// avoid infinite recursion
1210 AssocArray!(Type, size_t) types; /// Type => (offset+1) in buf
1211 AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf
1215 /***********************
1216 * Mangle basic type ty to buf.
1219 private void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe
1221 const c = mangleChar[ty];
1222 buf.writeByte(c);
1223 if (c == 'z')
1224 buf.writeByte(ty == Tint128 ? 'i' : 'k');
1227 /*********************************
1228 * Mangling for mod.
1230 private void MODtoDecoBuffer(ref OutBuffer buf, MOD mod) @safe
1232 switch (mod)
1234 case 0:
1235 break;
1236 case MODFlags.const_:
1237 buf.writeByte('x');
1238 break;
1239 case MODFlags.immutable_:
1240 buf.writeByte('y');
1241 break;
1242 case MODFlags.shared_:
1243 buf.writeByte('O');
1244 break;
1245 case MODFlags.shared_ | MODFlags.const_:
1246 buf.writestring("Ox");
1247 break;
1248 case MODFlags.wild:
1249 buf.writestring("Ng");
1250 break;
1251 case MODFlags.wildconst:
1252 buf.writestring("Ngx");
1253 break;
1254 case MODFlags.shared_ | MODFlags.wild:
1255 buf.writestring("ONg");
1256 break;
1257 case MODFlags.shared_ | MODFlags.wildconst:
1258 buf.writestring("ONgx");
1259 break;
1260 default:
1261 assert(0);
1267 * writes a back reference with the relative position encoded with base 26
1268 * using upper case letters for all digits but the last digit which uses
1269 * a lower case letter.
1270 * The decoder has to look up the referenced position to determine
1271 * whether the back reference is an identifier (starts with a digit)
1272 * or a type (starts with a letter).
1274 * Params:
1275 * buf = buffer to write to
1276 * pos = relative position to encode
1278 private
1279 void writeBackRef(ref OutBuffer buf, size_t pos) @safe
1281 buf.writeByte('Q');
1282 enum base = 26;
1283 size_t mul = 1;
1284 while (pos >= mul * base)
1285 mul *= base;
1286 while (mul >= base)
1288 auto dig = cast(ubyte)(pos / mul);
1289 buf.writeByte('A' + dig);
1290 pos -= dig * mul;
1291 mul /= base;
1293 buf.writeByte('a' + cast(ubyte)pos);
1297 /************************************************************
1298 * Write length prefixed string to buf.
1300 private
1301 extern (D) void toBuffer(ref OutBuffer buf, const(char)[] id, Dsymbol s)
1303 const len = id.length;
1304 if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
1305 error(s.loc, "%s `%s` excessive length %llu for symbol, possible recursive expansion?", s.kind, s.toPrettyChars, cast(ulong)(buf.length + len));
1306 else
1308 buf.print(len);
1309 buf.writestring(id);
1314 /*****
1315 * There can be multiple different declarations in the same
1316 * function that have the same mangled name.
1317 * This results in localNum having a non-zero number, which
1318 * is used to add a fake parent of the form `__Sddd` to make
1319 * the mangled names unique.
1320 * https://issues.dlang.org/show_bug.cgi?id=20565
1321 * Params:
1322 * buf = buffer to write to
1323 * localNum = local symbol number
1325 private
1326 void writeLocalParent(ref OutBuffer buf, uint localNum)
1328 uint ndigits = 1;
1329 auto n = localNum;
1330 while (n >= 10)
1332 n /= 10;
1333 ++ndigits;
1335 buf.printf("%u__S%u", ndigits + 3, localNum);
1338 /*************************
1339 * Write real to buffer.
1340 * Params:
1341 * buf = buffer to write to
1342 * value = real to write
1344 private
1345 void realToMangleBuffer(ref OutBuffer buf, real_t value)
1347 /* Rely on %A to get portable mangling.
1348 * Must munge result to get only identifier characters.
1350 * Possible values from %A => mangled result
1351 * NAN => NAN
1352 * -INF => NINF
1353 * INF => INF
1354 * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
1355 * 0X1.9P+2 => 19P2
1357 if (CTFloat.isNaN(value))
1359 buf.writestring("NAN"); // no -NAN bugs
1360 return;
1363 if (value < CTFloat.zero)
1365 buf.writeByte('N');
1366 value = -value;
1369 if (CTFloat.isInfinity(value))
1371 buf.writestring("INF");
1372 return;
1375 char[36] buffer = void;
1376 // 'A' format yields [-]0xh.hhhhp+-d
1377 const n = CTFloat.sprint(buffer.ptr, buffer.length, 'A', value);
1378 assert(n < buffer.length);
1379 foreach (const c; buffer[2 .. n])
1381 switch (c)
1383 case '-':
1384 buf.writeByte('N');
1385 break;
1387 case '+':
1388 case '.':
1389 break;
1391 default:
1392 buf.writeByte(c);
1393 break;
1398 /************************************************************
1399 * Try to obtain an externally mangled identifier from a declaration.
1400 * If the declaration is at global scope or mixed in at global scope,
1401 * the user might want to call it externally, so an externally mangled
1402 * name is returned. Member functions or nested functions can't be called
1403 * externally in C, so in that case null is returned. C++ does support
1404 * namespaces, so extern(C++) always gives a C++ mangled name.
1406 * See also: https://issues.dlang.org/show_bug.cgi?id=20012
1408 * Params:
1409 * d = declaration to mangle
1411 * Returns:
1412 * an externally mangled name or null if the declaration cannot be called externally
1414 private
1415 extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
1417 assert(!d.mangleOverride, "mangle overrides should have been handled earlier");
1419 const linkage = d.resolvedLinkage();
1420 const par = d.toParent(); //toParent() skips over mixin templates
1421 if (!par || par.isModule() || linkage == LINK.cpp ||
1422 (linkage == LINK.c && d.isCsymbol() &&
1423 (d.isFuncDeclaration() ||
1424 (d.isVarDeclaration() && d.isDataseg() && d.storage_class & STC.extern_))))
1426 if (linkage != LINK.d && d.localNum)
1427 error(d.loc, "%s `%s` the same declaration cannot be in multiple scopes with non-D linkage", d.kind, d.toPrettyChars);
1429 final switch (linkage)
1431 case LINK.d:
1432 break;
1433 case LINK.c:
1434 case LINK.windows:
1435 case LINK.objc:
1436 return d.ident.toString();
1437 case LINK.cpp:
1439 const p = target.cpp.toMangle(d);
1440 return p.toDString();
1442 case LINK.default_:
1443 error(d.loc, "%s `%s` forward declaration", d.kind, d.toPrettyChars);
1444 return d.ident.toString();
1445 case LINK.system:
1446 assert(0);
1449 return null;