MATCH: Improve `A CMP 0 ? A : -A` set of patterns to use bitwise_equal_p.
[official-gcc.git] / gcc / d / dmd / dmangle.d
blob9b72308971292555d2dfb11341bf05bb4c320f24
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.expression;
146 import dmd.func;
147 import dmd.globals;
148 import dmd.id;
149 import dmd.identifier;
150 import dmd.mtype;
151 import dmd.root.ctfloat;
152 import dmd.common.outbuffer;
153 import dmd.root.aav;
154 import dmd.root.string;
155 import dmd.root.stringtable;
156 import dmd.root.utf;
157 import dmd.target;
158 import dmd.tokens;
159 import dmd.visitor;
161 private immutable char[TMAX] mangleChar =
163 Tchar : 'a',
164 Tbool : 'b',
165 Tcomplex80 : 'c',
166 Tfloat64 : 'd',
167 Tfloat80 : 'e',
168 Tfloat32 : 'f',
169 Tint8 : 'g',
170 Tuns8 : 'h',
171 Tint32 : 'i',
172 Timaginary80 : 'j',
173 Tuns32 : 'k',
174 Tint64 : 'l',
175 Tuns64 : 'm',
176 Tnull : 'n',
177 Timaginary32 : 'o',
178 Timaginary64 : 'p',
179 Tcomplex32 : 'q',
180 Tcomplex64 : 'r',
181 Tint16 : 's',
182 Tuns16 : 't',
183 Twchar : 'u',
184 Tvoid : 'v',
185 Tdchar : 'w',
186 // x // const
187 // y // immutable
188 Tint128 : 'z', // zi
189 Tuns128 : 'z', // zk
191 Tarray : 'A',
192 Ttuple : 'B',
193 Tclass : 'C',
194 Tdelegate : 'D',
195 Tenum : 'E',
196 Tfunction : 'F', // D function
197 Tsarray : 'G',
198 Taarray : 'H',
199 // I // in
200 // J // out
201 // K // ref
202 // L // lazy
203 // M // has this, or scope
204 // N // Nh:vector Ng:wild Nn:noreturn
205 // O // shared
206 Tpointer : 'P',
207 // Q // Type/symbol/identifier backward reference
208 Treference : 'R',
209 Tstruct : 'S',
210 // T // Ttypedef
211 // U // C function
212 // W // Windows function
213 // X // variadic T t...)
214 // Y // variadic T t,...)
215 // Z // not variadic, end of parameters
217 // '@' shouldn't appear anywhere in the deco'd names
218 Tnone : '@',
219 Tident : '@',
220 Tinstance : '@',
221 Terror : '@',
222 Ttypeof : '@',
223 Tslice : '@',
224 Treturn : '@',
225 Tvector : '@',
226 Ttraits : '@',
227 Tmixin : '@',
228 Ttag : '@',
229 Tnoreturn : '@', // becomes 'Nn'
232 unittest
234 foreach (i, mangle; mangleChar)
236 if (mangle == char.init)
238 fprintf(stderr, "ty = %u\n", cast(uint)i);
239 assert(0);
244 /************************************************
245 * Append the mangling of type `t` to `buf`.
246 * Params:
247 * t = type to mangle
248 * modMask = mod bits currently applying to t
249 * buf = buffer to append mangling to
250 * backref = state of back references (updated)
252 void mangleType(Type t, ubyte modMask, ref OutBuffer buf, ref Backref backref)
254 void visitWithMask(Type t, ubyte modMask)
256 void mangleSymbol(Dsymbol s)
258 scope Mangler v = new Mangler(buf, &backref);
259 v.mangleSymbol(s);
262 void visitType(Type t)
264 tyToDecoBuffer(buf, t.ty);
267 void visitTypeNext(TypeNext t)
269 visitType(t);
270 visitWithMask(t.next, t.mod);
273 void visitTypeVector(TypeVector t)
275 buf.writestring("Nh");
276 visitWithMask(t.basetype, t.mod);
279 void visitTypeSArray(TypeSArray t)
281 visitType(t);
282 if (t.dim)
283 buf.print(t.dim.toInteger());
284 if (t.next)
285 visitWithMask(t.next, t.mod);
288 void visitTypeDArray(TypeDArray t)
290 visitType(t);
291 if (t.next)
292 visitWithMask(t.next, t.mod);
295 void visitTypeAArray(TypeAArray t)
297 visitType(t);
298 visitWithMask(t.index, 0);
299 visitWithMask(t.next, t.mod);
302 void visitTypeFunction(TypeFunction t)
304 //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
305 //static int nest; if (++nest == 50) *(char*)0=0;
306 mangleFuncType(t, t, t.mod, t.next, buf, backref);
309 void visitTypeIdentifier(TypeIdentifier t)
311 visitType(t);
312 auto name = t.ident.toString();
313 buf.print(cast(int)name.length);
314 buf.writestring(name);
317 void visitTypeEnum(TypeEnum t)
319 visitType(t);
320 mangleSymbol(t.sym);
323 void visitTypeStruct(TypeStruct t)
325 //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
326 visitType(t);
327 mangleSymbol(t.sym);
330 void visitTypeClass(TypeClass t)
332 //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
333 visitType(t);
334 mangleSymbol(t.sym);
337 void visitTypeTuple(TypeTuple t)
339 //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
340 visitType(t);
341 Parameter._foreach(t.arguments, (idx, param) {
342 mangleParameter(param, buf, backref);
343 return 0;
345 buf.writeByte('Z');
348 void visitTypeNull(TypeNull t)
350 visitType(t);
353 void visitTypeNoreturn(TypeNoreturn t)
355 buf.writestring("Nn");
358 if (modMask != t.mod)
360 MODtoDecoBuffer(buf, t.mod);
362 if (backref.addRefToType(buf, t))
363 return;
365 switch (t.ty)
367 case Tpointer:
368 case Treference:
369 case Tdelegate:
370 case Tslice: visitTypeNext (cast(TypeNext)t); break;
372 case Tarray: visitTypeDArray (t.isTypeDArray()); break;
373 case Tsarray: visitTypeSArray (t.isTypeSArray()); break;
374 case Taarray: visitTypeAArray (t.isTypeAArray()); break;
375 case Tfunction: visitTypeFunction (t.isTypeFunction()); break;
376 case Tident: visitTypeIdentifier(t.isTypeIdentifier()); break;
377 case Tclass: visitTypeClass (t.isTypeClass()); break;
378 case Tstruct: visitTypeStruct (t.isTypeStruct()); break;
379 case Tenum: visitTypeEnum (t.isTypeEnum()); break;
380 case Ttuple: visitTypeTuple (t.isTypeTuple()); break;
381 case Tnull: visitTypeNull (t.isTypeNull()); break;
382 case Tvector: visitTypeVector (t.isTypeVector()); break;
383 case Tnoreturn: visitTypeNoreturn (t.isTypeNoreturn); break;
385 case Terror:
386 break; // ignore errors
388 default: visitType(t); break;
392 visitWithMask(t, modMask);
396 /*************************************************************
398 void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret, ref OutBuffer buf, ref Backref backref)
400 //printf("mangleFuncType() %s\n", t.toChars());
401 if (t.inuse && tret)
403 // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
404 t.inuse = 2; // flag error to caller
405 return;
407 t.inuse++;
408 if (modMask != t.mod)
409 MODtoDecoBuffer(buf, t.mod);
411 char mc;
412 final switch (t.linkage)
414 case LINK.default_:
415 case LINK.d:
416 mc = 'F';
417 break;
418 case LINK.c:
419 mc = 'U';
420 break;
421 case LINK.windows:
422 mc = 'W';
423 break;
424 case LINK.cpp:
425 mc = 'R';
426 break;
427 case LINK.objc:
428 mc = 'Y';
429 break;
430 case LINK.system:
431 assert(0);
433 buf.writeByte(mc);
435 if (ta.purity)
436 buf.writestring("Na");
437 if (ta.isnothrow)
438 buf.writestring("Nb");
439 if (ta.isref)
440 buf.writestring("Nc");
441 if (ta.isproperty)
442 buf.writestring("Nd");
443 if (ta.isnogc)
444 buf.writestring("Ni");
446 // `return scope` must be in that order
447 if (ta.isreturnscope && !ta.isreturninferred)
449 buf.writestring("NjNl");
451 else
453 // when return ref, the order is `scope return`
454 if (ta.isScopeQual && !ta.isscopeinferred)
455 buf.writestring("Nl");
457 if (ta.isreturn && !ta.isreturninferred)
458 buf.writestring("Nj");
461 if (ta.islive)
462 buf.writestring("Nm");
464 switch (ta.trust)
466 case TRUST.trusted:
467 buf.writestring("Ne");
468 break;
469 case TRUST.safe:
470 buf.writestring("Nf");
471 break;
472 default:
473 break;
476 // Write argument types
477 foreach (idx, param; t.parameterList)
478 mangleParameter(param, buf, backref);
479 //if (buf.data[buf.length - 1] == '@') assert(0);
480 buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
481 if (tret !is null)
482 mangleType(tret, 0, buf, backref);
483 t.inuse--;
486 /*************************************************************
488 void mangleParameter(Parameter p, ref OutBuffer buf, ref Backref backref)
490 // https://dlang.org/spec/abi.html#Parameter
492 auto stc = p.storageClass;
494 // Inferred storage classes don't get mangled in
495 if (stc & STC.scopeinferred)
496 stc &= ~(STC.scope_ | STC.scopeinferred);
497 if (stc & STC.returninferred)
498 stc &= ~(STC.return_ | STC.returninferred);
500 // much like hdrgen.stcToBuffer()
501 string rrs;
502 const isout = (stc & STC.out_) != 0;
503 final switch (buildScopeRef(stc))
505 case ScopeRef.None:
506 case ScopeRef.Scope:
507 case ScopeRef.Ref:
508 case ScopeRef.Return:
509 case ScopeRef.RefScope:
510 break;
512 case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope
513 case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref
514 case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref
515 case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref
517 buf.writestring(rrs);
518 stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
519 break;
522 if (stc & STC.scope_)
523 buf.writeByte('M'); // scope
525 if (stc & STC.return_)
526 buf.writestring("Nk"); // return
528 switch (stc & (STC.IOR | STC.lazy_))
530 case 0:
531 break;
532 case STC.in_:
533 buf.writeByte('I');
534 break;
535 case STC.in_ | STC.ref_:
536 buf.writestring("IK");
537 break;
538 case STC.out_:
539 buf.writeByte('J');
540 break;
541 case STC.ref_:
542 buf.writeByte('K');
543 break;
544 case STC.lazy_:
545 buf.writeByte('L');
546 break;
547 default:
548 debug
550 printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_));
552 assert(0);
554 mangleType(p.type, (stc & STC.in_) ? MODFlags.const_ : 0, buf, backref);
558 private extern (C++) final class Mangler : Visitor
560 alias visit = Visitor.visit;
561 public:
562 static assert(Key.sizeof == size_t.sizeof);
564 OutBuffer* buf;
565 Backref* backref;
567 extern (D) this(ref OutBuffer buf, Backref* backref) @trusted
569 this.buf = &buf;
570 this.backref = backref;
573 void mangleSymbol(Dsymbol s)
575 s.accept(this);
578 void mangleIdentifier(Identifier id, Dsymbol s)
580 if (!backref.addRefToIdentifier(*buf, id))
581 toBuffer(*buf, id.toString(), s);
584 ////////////////////////////////////////////////////////////////////////////
585 void mangleDecl(Declaration sthis)
587 mangleParent(sthis);
588 assert(sthis.ident);
589 mangleIdentifier(sthis.ident, sthis);
590 if (FuncDeclaration fd = sthis.isFuncDeclaration())
592 mangleFunc(fd, false);
594 else if (sthis.type)
596 mangleType(sthis.type, 0, *buf, *backref);
598 else
599 assert(0);
602 void mangleParent(Dsymbol s)
604 //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
605 Dsymbol p;
606 if (TemplateInstance ti = s.isTemplateInstance())
607 p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent;
608 else
609 p = s.parent;
610 if (p)
612 uint localNum = s.localNum;
613 mangleParent(p);
614 auto ti = p.isTemplateInstance();
615 if (ti && !ti.isTemplateMixin())
617 localNum = ti.tempdecl.localNum;
618 mangleTemplateInstance(ti);
620 else if (p.getIdent())
622 mangleIdentifier(p.ident, s);
623 if (FuncDeclaration f = p.isFuncDeclaration())
624 mangleFunc(f, true);
626 else
627 buf.writeByte('0');
629 if (localNum)
630 writeLocalParent(*buf, localNum);
634 void mangleFunc(FuncDeclaration fd, bool inParent)
636 //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
637 //printf("fd.type = %s\n", fd.type.toChars());
638 if (fd.needThis() || fd.isNested())
639 buf.writeByte('M');
641 if (!fd.type || fd.type.ty == Terror)
643 // never should have gotten here, but could be the result of
644 // failed speculative compilation
645 buf.writestring("9__error__FZ");
647 //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars());
648 //assert(0); // don't mangle function until semantic3 done.
650 else if (inParent)
652 TypeFunction tf = fd.type.isTypeFunction();
653 TypeFunction tfo = fd.originalType.isTypeFunction();
654 mangleFuncType(tf, tfo, 0, null, *buf, *backref);
656 else
658 mangleType(fd.type, 0, *buf, *backref);
662 override void visit(Declaration d)
664 //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
665 // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
666 if (const id = externallyMangledIdentifier(d))
668 buf.writestring(id);
669 return;
671 buf.writestring("_D");
672 mangleDecl(d);
673 debug
675 const slice = (*buf)[];
676 assert(slice.length);
677 for (size_t pos; pos < slice.length; )
679 dchar c;
680 auto ppos = pos;
681 const s = utf_decodeChar(slice, pos, c);
682 assert(s is null, s);
683 assert(c.isValidMangling, "The mangled name '" ~ slice ~ "' " ~
684 "contains an invalid character: " ~ slice[ppos..pos]);
689 /******************************************************************************
690 * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
691 * If and only if there is no overloads, mangle() could return
692 * exact mangled name.
694 * module test;
695 * void foo(long) {} // _D4test3fooFlZv
696 * void foo(string) {} // _D4test3fooFAyaZv
698 * // from FuncDeclaration.mangle().
699 * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
700 * // by calling Dsymbol.mangle()
702 * // from FuncAliasDeclaration.mangle()
703 * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
704 * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
706 * If a function has no overloads, .mangleof property still returns exact mangled name.
708 * void bar() {}
709 * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
710 * // by calling FuncDeclaration.mangleExact().
712 override void visit(FuncDeclaration fd)
714 if (fd.isUnique())
715 mangleExact(fd);
716 else
717 visit(cast(Dsymbol)fd);
720 // ditto
721 override void visit(FuncAliasDeclaration fd)
723 FuncDeclaration f = fd.toAliasFunc();
724 FuncAliasDeclaration fa = f.isFuncAliasDeclaration();
725 if (!fd.hasOverloads && !fa)
727 mangleExact(f);
728 return;
730 if (fa)
732 mangleSymbol(fa);
733 return;
735 visit(cast(Dsymbol)fd);
738 override void visit(OverDeclaration od)
740 if (od.overnext)
742 visit(cast(Dsymbol)od);
743 return;
745 if (FuncDeclaration fd = od.aliassym.isFuncDeclaration())
747 if (fd.isUnique())
749 mangleExact(fd);
750 return;
753 if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration())
755 if (td.overnext is null)
757 mangleSymbol(td);
758 return;
761 visit(cast(Dsymbol)od);
764 void mangleExact(FuncDeclaration fd)
766 assert(!fd.isFuncAliasDeclaration());
767 if (fd.mangleOverride)
769 buf.writestring(fd.mangleOverride);
770 return;
772 if (fd.isMain())
774 buf.writestring("_Dmain");
775 return;
777 if (fd.isWinMain() || fd.isDllMain())
779 buf.writestring(fd.ident.toString());
780 return;
782 visit(cast(Declaration)fd);
785 override void visit(VarDeclaration vd)
787 if (vd.mangleOverride)
789 buf.writestring(vd.mangleOverride);
790 return;
792 visit(cast(Declaration)vd);
795 override void visit(AggregateDeclaration ad)
797 ClassDeclaration cd = ad.isClassDeclaration();
798 Dsymbol parentsave = ad.parent;
799 if (cd)
801 /* These are reserved to the compiler, so keep simple
802 * names for them.
804 if (cd.ident == Id.Exception && cd.parent.ident == Id.object || cd.ident == Id.TypeInfo || cd.ident == Id.TypeInfo_Struct || cd.ident == Id.TypeInfo_Class || cd.ident == Id.TypeInfo_Tuple || cd == ClassDeclaration.object || cd == Type.typeinfoclass || cd == Module.moduleinfo || strncmp(cd.ident.toChars(), "TypeInfo_", 9) == 0)
806 // Don't mangle parent
807 ad.parent = null;
810 visit(cast(Dsymbol)ad);
811 ad.parent = parentsave;
814 override void visit(TemplateInstance ti)
816 version (none)
818 printf("TemplateInstance.mangle() %p %s", ti, ti.toChars());
819 if (ti.parent)
820 printf(" parent = %s %s", ti.parent.kind(), ti.parent.toChars());
821 printf("\n");
823 if (!ti.tempdecl)
824 ti.error("is not defined");
825 else
826 mangleParent(ti);
828 if (ti.isTemplateMixin() && ti.ident)
829 mangleIdentifier(ti.ident, ti);
830 else
831 mangleTemplateInstance(ti);
834 void mangleTemplateInstance(TemplateInstance ti)
836 TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration();
837 assert(tempdecl);
839 // Use "__U" for the symbols declared inside template constraint.
840 const char T = ti.members ? 'T' : 'U';
841 buf.printf("__%c", T);
842 mangleIdentifier(tempdecl.ident, tempdecl);
844 auto args = ti.tiargs;
845 size_t nparams = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
846 for (size_t i = 0; i < args.length; i++)
848 auto o = (*args)[i];
849 Type ta = isType(o);
850 Expression ea = isExpression(o);
851 Dsymbol sa = isDsymbol(o);
852 Tuple va = isTuple(o);
853 //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
854 if (i < nparams && (*tempdecl.parameters)[i].specialization())
855 buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
856 if (ta)
858 buf.writeByte('T');
859 mangleType(ta, 0, *buf, *backref);
861 else if (ea)
863 // Don't interpret it yet, it might actually be an alias template parameter.
864 // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
865 enum keepLvalue = true;
866 ea = ea.optimize(WANTvalue, keepLvalue);
867 if (auto ev = ea.isVarExp())
869 sa = ev.var;
870 ea = null;
871 goto Lsa;
873 if (auto et = ea.isThisExp())
875 sa = et.var;
876 ea = null;
877 goto Lsa;
879 if (auto ef = ea.isFuncExp())
881 if (ef.td)
882 sa = ef.td;
883 else
884 sa = ef.fd;
885 ea = null;
886 goto Lsa;
888 buf.writeByte('V');
889 if (ea.op == EXP.tuple)
891 ea.error("sequence is not a valid template value argument");
892 continue;
894 // Now that we know it is not an alias, we MUST obtain a value
895 uint olderr = global.errors;
896 ea = ea.ctfeInterpret();
897 if (ea.op == EXP.error || olderr != global.errors)
898 continue;
900 /* Use type mangling that matches what it would be for a function parameter
902 mangleType(ea.type, 0, *buf, *backref);
903 ea.accept(this);
905 else if (sa)
907 Lsa:
908 sa = sa.toAlias();
909 if (sa.isDeclaration() && !sa.isOverDeclaration())
911 Declaration d = sa.isDeclaration();
913 if (auto fad = d.isFuncAliasDeclaration())
914 d = fad.toAliasFunc();
915 if (d.mangleOverride)
917 buf.writeByte('X');
918 toBuffer(*buf, d.mangleOverride, d);
919 continue;
921 if (const id = externallyMangledIdentifier(d))
923 buf.writeByte('X');
924 toBuffer(*buf, id, d);
925 continue;
927 if (!d.type || !d.type.deco)
929 ti.error("forward reference of %s `%s`", d.kind(), d.toChars());
930 continue;
933 buf.writeByte('S');
934 mangleSymbol(sa);
936 else if (va)
938 assert(i + 1 == args.length); // must be last one
939 args = &va.objects;
940 i = -cast(size_t)1;
942 else
943 assert(0);
945 buf.writeByte('Z');
948 override void visit(Dsymbol s)
950 version (none)
952 printf("Dsymbol.mangle() '%s'", s.toChars());
953 if (s.parent)
954 printf(" parent = %s %s", s.parent.kind(), s.parent.toChars());
955 printf("\n");
957 if (s.parent && s.ident)
959 if (auto m = s.parent.isModule())
961 if (m.filetype == FileType.c)
963 /* C types at global level get mangled into the __C global namespace
964 * to get the same mangling regardless of which module it
965 * is declared in. This works because types are the same if the mangling
966 * is the same.
968 mangleIdentifier(Id.ImportC, s); // parent
969 mangleIdentifier(s.ident, s);
970 return;
974 mangleParent(s);
975 if (s.ident)
976 mangleIdentifier(s.ident, s);
977 else
978 toBuffer(*buf, s.toString(), s);
979 //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
982 ////////////////////////////////////////////////////////////////////////////
983 override void visit(Expression e)
985 e.error("expression `%s` is not a valid template value argument", e.toChars());
988 override void visit(IntegerExp e)
990 const v = e.toInteger();
991 if (cast(sinteger_t)v < 0)
993 buf.writeByte('N');
994 buf.print(-v);
996 else
998 buf.writeByte('i');
999 buf.print(v);
1003 override void visit(RealExp e)
1005 buf.writeByte('e');
1006 realToMangleBuffer(*buf, e.value);
1009 override void visit(ComplexExp e)
1011 buf.writeByte('c');
1012 realToMangleBuffer(*buf, e.toReal());
1013 buf.writeByte('c'); // separate the two
1014 realToMangleBuffer(*buf, e.toImaginary());
1017 override void visit(NullExp e)
1019 buf.writeByte('n');
1022 override void visit(StringExp e)
1024 char m;
1025 OutBuffer tmp;
1026 const(char)[] q;
1027 /* Write string in UTF-8 format
1029 switch (e.sz)
1031 case 1:
1032 m = 'a';
1033 q = e.peekString();
1034 break;
1035 case 2:
1037 m = 'w';
1038 const slice = e.peekWstring();
1039 for (size_t u = 0; u < e.len;)
1041 dchar c;
1042 if (const s = utf_decodeWchar(slice, u, c))
1043 e.error("%.*s", cast(int)s.length, s.ptr);
1044 else
1045 tmp.writeUTF8(c);
1047 q = tmp[];
1048 break;
1050 case 4:
1052 m = 'd';
1053 const slice = e.peekDstring();
1054 foreach (c; slice)
1056 if (!utf_isValidDchar(c))
1057 e.error("invalid UCS-32 char \\U%08x", c);
1058 else
1059 tmp.writeUTF8(c);
1061 q = tmp[];
1062 break;
1065 default:
1066 assert(0);
1068 buf.reserve(1 + 11 + 2 * q.length);
1069 buf.writeByte(m);
1070 buf.print(q.length);
1071 buf.writeByte('_'); // nbytes <= 11
1072 auto slice = buf.allocate(2 * q.length);
1073 foreach (i, c; q)
1075 char hi = (c >> 4) & 0xF;
1076 slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a');
1077 char lo = c & 0xF;
1078 slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a');
1082 override void visit(ArrayLiteralExp e)
1084 const dim = e.elements ? e.elements.length : 0;
1085 buf.writeByte('A');
1086 buf.print(dim);
1087 foreach (i; 0 .. dim)
1089 e[i].accept(this);
1093 override void visit(AssocArrayLiteralExp e)
1095 const dim = e.keys.length;
1096 buf.writeByte('A');
1097 buf.print(dim);
1098 foreach (i; 0 .. dim)
1100 (*e.keys)[i].accept(this);
1101 (*e.values)[i].accept(this);
1105 override void visit(StructLiteralExp e)
1107 const dim = e.elements ? e.elements.length : 0;
1108 buf.writeByte('S');
1109 buf.print(dim);
1110 foreach (i; 0 .. dim)
1112 Expression ex = (*e.elements)[i];
1113 if (ex)
1114 ex.accept(this);
1115 else
1116 buf.writeByte('v'); // 'v' for void
1120 override void visit(FuncExp e)
1122 buf.writeByte('f');
1123 if (e.td)
1124 mangleSymbol(e.td);
1125 else
1126 mangleSymbol(e.fd);
1130 /***************************************
1131 * Manage back reference mangling
1133 private struct Backref
1136 * Back references a non-basic type
1138 * The encoded mangling is
1139 * 'Q' <relative position of first occurrence of type>
1141 * Params:
1142 * t = the type to encode via back referencing
1144 * Returns:
1145 * true if the type was found. A back reference has been encoded.
1146 * false if the type was not found. The current position is saved for later back references.
1148 bool addRefToType(ref OutBuffer buf, Type t)
1150 if (t.isTypeBasic())
1151 return false;
1154 * https://issues.dlang.org/show_bug.cgi?id=21591
1156 * Special case for unmerged TypeFunctions: use the generic merged
1157 * function type as backref cache key to avoid missed backrefs.
1159 * Merging is based on mangling, so we need to avoid an infinite
1160 * recursion by excluding the case where `t` is the root type passed to
1161 * `mangleToBuffer()`.
1163 if (t != rootType)
1165 if (t.isFunction_Delegate_PtrToFunction())
1167 t = t.merge2();
1171 return backrefImpl(buf, types, t);
1175 * Back references a single identifier
1177 * The encoded mangling is
1178 * 'Q' <relative position of first occurrence of type>
1180 * Params:
1181 * id = the identifier to encode via back referencing
1183 * Returns:
1184 * true if the identifier was found. A back reference has been encoded.
1185 * false if the identifier was not found. The current position is saved for later back references.
1187 bool addRefToIdentifier(ref OutBuffer buf, Identifier id)
1189 return backrefImpl(buf, idents, id);
1192 private:
1194 extern(D) bool backrefImpl(T)(ref OutBuffer buf, ref AssocArray!(T, size_t) aa, T key)
1196 auto p = aa.getLvalue(key);
1197 if (*p)
1199 const offset = *p - 1;
1200 writeBackRef(buf, buf.length - offset);
1201 return true;
1203 *p = buf.length + 1;
1204 return false;
1207 Type rootType; /// avoid infinite recursion
1208 AssocArray!(Type, size_t) types; /// Type => (offset+1) in buf
1209 AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf
1213 /***********************
1214 * Mangle basic type ty to buf.
1217 private void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe
1219 const c = mangleChar[ty];
1220 buf.writeByte(c);
1221 if (c == 'z')
1222 buf.writeByte(ty == Tint128 ? 'i' : 'k');
1225 /*********************************
1226 * Mangling for mod.
1228 private void MODtoDecoBuffer(ref OutBuffer buf, MOD mod) @safe
1230 switch (mod)
1232 case 0:
1233 break;
1234 case MODFlags.const_:
1235 buf.writeByte('x');
1236 break;
1237 case MODFlags.immutable_:
1238 buf.writeByte('y');
1239 break;
1240 case MODFlags.shared_:
1241 buf.writeByte('O');
1242 break;
1243 case MODFlags.shared_ | MODFlags.const_:
1244 buf.writestring("Ox");
1245 break;
1246 case MODFlags.wild:
1247 buf.writestring("Ng");
1248 break;
1249 case MODFlags.wildconst:
1250 buf.writestring("Ngx");
1251 break;
1252 case MODFlags.shared_ | MODFlags.wild:
1253 buf.writestring("ONg");
1254 break;
1255 case MODFlags.shared_ | MODFlags.wildconst:
1256 buf.writestring("ONgx");
1257 break;
1258 default:
1259 assert(0);
1265 * writes a back reference with the relative position encoded with base 26
1266 * using upper case letters for all digits but the last digit which uses
1267 * a lower case letter.
1268 * The decoder has to look up the referenced position to determine
1269 * whether the back reference is an identifier (starts with a digit)
1270 * or a type (starts with a letter).
1272 * Params:
1273 * buf = buffer to write to
1274 * pos = relative position to encode
1276 private
1277 void writeBackRef(ref OutBuffer buf, size_t pos) @safe
1279 buf.writeByte('Q');
1280 enum base = 26;
1281 size_t mul = 1;
1282 while (pos >= mul * base)
1283 mul *= base;
1284 while (mul >= base)
1286 auto dig = cast(ubyte)(pos / mul);
1287 buf.writeByte('A' + dig);
1288 pos -= dig * mul;
1289 mul /= base;
1291 buf.writeByte('a' + cast(ubyte)pos);
1295 /************************************************************
1296 * Write length prefixed string to buf.
1298 private
1299 extern (D) void toBuffer(ref OutBuffer buf, const(char)[] id, Dsymbol s)
1301 const len = id.length;
1302 if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
1303 s.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf.length + len));
1304 else
1306 buf.print(len);
1307 buf.writestring(id);
1312 /*****
1313 * There can be multiple different declarations in the same
1314 * function that have the same mangled name.
1315 * This results in localNum having a non-zero number, which
1316 * is used to add a fake parent of the form `__Sddd` to make
1317 * the mangled names unique.
1318 * https://issues.dlang.org/show_bug.cgi?id=20565
1319 * Params:
1320 * buf = buffer to write to
1321 * localNum = local symbol number
1323 private
1324 void writeLocalParent(ref OutBuffer buf, uint localNum)
1326 uint ndigits = 1;
1327 auto n = localNum;
1328 while (n >= 10)
1330 n /= 10;
1331 ++ndigits;
1333 buf.printf("%u__S%u", ndigits + 3, localNum);
1336 /*************************
1337 * Write real to buffer.
1338 * Params:
1339 * buf = buffer to write to
1340 * value = real to write
1342 private
1343 void realToMangleBuffer(ref OutBuffer buf, real_t value)
1345 /* Rely on %A to get portable mangling.
1346 * Must munge result to get only identifier characters.
1348 * Possible values from %A => mangled result
1349 * NAN => NAN
1350 * -INF => NINF
1351 * INF => INF
1352 * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
1353 * 0X1.9P+2 => 19P2
1355 if (CTFloat.isNaN(value))
1357 buf.writestring("NAN"); // no -NAN bugs
1358 return;
1361 if (value < CTFloat.zero)
1363 buf.writeByte('N');
1364 value = -value;
1367 if (CTFloat.isInfinity(value))
1369 buf.writestring("INF");
1370 return;
1373 char[36] buffer = void;
1374 // 'A' format yields [-]0xh.hhhhp+-d
1375 const n = CTFloat.sprint(buffer.ptr, buffer.length, 'A', value);
1376 assert(n < buffer.length);
1377 foreach (const c; buffer[2 .. n])
1379 switch (c)
1381 case '-':
1382 buf.writeByte('N');
1383 break;
1385 case '+':
1386 case '.':
1387 break;
1389 default:
1390 buf.writeByte(c);
1391 break;
1396 /************************************************************
1397 * Try to obtain an externally mangled identifier from a declaration.
1398 * If the declaration is at global scope or mixed in at global scope,
1399 * the user might want to call it externally, so an externally mangled
1400 * name is returned. Member functions or nested functions can't be called
1401 * externally in C, so in that case null is returned. C++ does support
1402 * namespaces, so extern(C++) always gives a C++ mangled name.
1404 * See also: https://issues.dlang.org/show_bug.cgi?id=20012
1406 * Params:
1407 * d = declaration to mangle
1409 * Returns:
1410 * an externally mangled name or null if the declaration cannot be called externally
1412 private
1413 extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
1415 assert(!d.mangleOverride, "mangle overrides should have been handled earlier");
1417 const linkage = d.resolvedLinkage();
1418 const par = d.toParent(); //toParent() skips over mixin templates
1419 if (!par || par.isModule() || linkage == LINK.cpp ||
1420 (linkage == LINK.c && d.isCsymbol() &&
1421 (d.isFuncDeclaration() ||
1422 (d.isVarDeclaration() && d.isDataseg() && d.storage_class & STC.extern_))))
1424 if (linkage != LINK.d && d.localNum)
1425 d.error("the same declaration cannot be in multiple scopes with non-D linkage");
1427 final switch (linkage)
1429 case LINK.d:
1430 break;
1431 case LINK.c:
1432 case LINK.windows:
1433 case LINK.objc:
1434 return d.ident.toString();
1435 case LINK.cpp:
1437 const p = target.cpp.toMangle(d);
1438 return p.toDString();
1440 case LINK.default_:
1441 d.error("forward declaration");
1442 return d.ident.toString();
1443 case LINK.system:
1444 assert(0);
1447 return null;